@@ -1901,6 +1901,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
1901
1901
}
1902
1902
list_free (relation -> rd_indexlist );
1903
1903
bms_free (relation -> rd_indexattr );
1904
+ bms_free (relation -> rd_keyattr );
1905
+ bms_free (relation -> rd_idattr );
1904
1906
FreeTriggerDesc (relation -> trigdesc );
1905
1907
if (relation -> rd_options )
1906
1908
pfree (relation -> rd_options );
@@ -2547,6 +2549,7 @@ AtEOXact_cleanup(Relation relation, bool isCommit)
2547
2549
list_free (relation -> rd_indexlist );
2548
2550
relation -> rd_indexlist = NIL ;
2549
2551
relation -> rd_oidindex = InvalidOid ;
2552
+ relation -> rd_replidindex = InvalidOid ;
2550
2553
relation -> rd_indexvalid = 0 ;
2551
2554
}
2552
2555
}
@@ -2645,6 +2648,7 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit,
2645
2648
list_free (relation -> rd_indexlist );
2646
2649
relation -> rd_indexlist = NIL ;
2647
2650
relation -> rd_oidindex = InvalidOid ;
2651
+ relation -> rd_replidindex = InvalidOid ;
2648
2652
relation -> rd_indexvalid = 0 ;
2649
2653
}
2650
2654
}
@@ -3596,6 +3600,10 @@ CheckConstraintFetch(Relation relation)
3596
3600
* of the index list. rd_oidindex is valid when rd_indexvalid isn't zero;
3597
3601
* it is the pg_class OID of a unique index on OID when the relation has one,
3598
3602
* and InvalidOid if there is no such index.
3603
+ *
3604
+ * In exactly the same way, we update rd_replidindex, which is the pg_class
3605
+ * OID of an index to be used as the relation's replication identity index,
3606
+ * or InvalidOid if there is no such index.
3599
3607
*/
3600
3608
List *
3601
3609
RelationGetIndexList (Relation relation )
@@ -3667,8 +3675,8 @@ RelationGetIndexList(Relation relation)
3667
3675
3668
3676
/*
3669
3677
* Invalid, non-unique, non-immediate or predicate indexes aren't
3670
- * interesting for neither oid indexes nor replication identity
3671
- * indexes, so don't check them.
3678
+ * interesting for either oid indexes or replication identity indexes,
3679
+ * so don't check them.
3672
3680
*/
3673
3681
if (!IndexIsValid (index ) || !index -> indisunique ||
3674
3682
!index -> indimmediate ||
@@ -3681,35 +3689,29 @@ RelationGetIndexList(Relation relation)
3681
3689
indclass -> values [0 ] == OID_BTREE_OPS_OID )
3682
3690
oidIndex = index -> indexrelid ;
3683
3691
3684
- /* always prefer primary keys */
3692
+ /* remember primary key index if any */
3685
3693
if (index -> indisprimary )
3686
3694
pkeyIndex = index -> indexrelid ;
3687
3695
3688
- /* explicitly chosen index */
3696
+ /* remember explicitly chosen replica index */
3689
3697
if (index -> indisreplident )
3690
3698
candidateIndex = index -> indexrelid ;
3691
3699
}
3692
3700
3693
3701
systable_endscan (indscan );
3694
3702
3695
- /* primary key */
3696
- if (replident == REPLICA_IDENTITY_DEFAULT &&
3697
- OidIsValid (pkeyIndex ))
3698
- relation -> rd_replidindex = pkeyIndex ;
3699
- /* explicitly chosen index */
3700
- else if (replident == REPLICA_IDENTITY_INDEX &&
3701
- OidIsValid (candidateIndex ))
3702
- relation -> rd_replidindex = candidateIndex ;
3703
- /* nothing */
3704
- else
3705
- relation -> rd_replidindex = InvalidOid ;
3706
-
3707
3703
heap_close (indrel , AccessShareLock );
3708
3704
3709
3705
/* Now save a copy of the completed list in the relcache entry. */
3710
3706
oldcxt = MemoryContextSwitchTo (CacheMemoryContext );
3711
3707
relation -> rd_indexlist = list_copy (result );
3712
3708
relation -> rd_oidindex = oidIndex ;
3709
+ if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid (pkeyIndex ))
3710
+ relation -> rd_replidindex = pkeyIndex ;
3711
+ else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid (candidateIndex ))
3712
+ relation -> rd_replidindex = candidateIndex ;
3713
+ else
3714
+ relation -> rd_replidindex = InvalidOid ;
3713
3715
relation -> rd_indexvalid = 1 ;
3714
3716
MemoryContextSwitchTo (oldcxt );
3715
3717
@@ -3767,7 +3769,8 @@ insert_ordered_oid(List *list, Oid datum)
3767
3769
* correctly with respect to the full index set. It is up to the caller
3768
3770
* to ensure that a correct rd_indexattr set has been cached before first
3769
3771
* calling RelationSetIndexList; else a subsequent inquiry might cause a
3770
- * wrong rd_indexattr set to get computed and cached.
3772
+ * wrong rd_indexattr set to get computed and cached. Likewise, we do not
3773
+ * touch rd_keyattr or rd_idattr.
3771
3774
*/
3772
3775
void
3773
3776
RelationSetIndexList (Relation relation , List * indexIds , Oid oidIndex )
@@ -3783,6 +3786,8 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
3783
3786
list_free (relation -> rd_indexlist );
3784
3787
relation -> rd_indexlist = indexIds ;
3785
3788
relation -> rd_oidindex = oidIndex ;
3789
+ /* For the moment, assume the target rel hasn't got a replica index */
3790
+ relation -> rd_replidindex = InvalidOid ;
3786
3791
relation -> rd_indexvalid = 2 ; /* mark list as forced */
3787
3792
/* Flag relation as needing eoxact cleanup (to reset the list) */
3788
3793
EOXactListAdd (relation );
@@ -3816,6 +3821,27 @@ RelationGetOidIndex(Relation relation)
3816
3821
return relation -> rd_oidindex ;
3817
3822
}
3818
3823
3824
+ /*
3825
+ * RelationGetReplicaIndex -- get OID of the relation's replica identity index
3826
+ *
3827
+ * Returns InvalidOid if there is no such index.
3828
+ */
3829
+ Oid
3830
+ RelationGetReplicaIndex (Relation relation )
3831
+ {
3832
+ List * ilist ;
3833
+
3834
+ if (relation -> rd_indexvalid == 0 )
3835
+ {
3836
+ /* RelationGetIndexList does the heavy lifting. */
3837
+ ilist = RelationGetIndexList (relation );
3838
+ list_free (ilist );
3839
+ Assert (relation -> rd_indexvalid != 0 );
3840
+ }
3841
+
3842
+ return relation -> rd_replidindex ;
3843
+ }
3844
+
3819
3845
/*
3820
3846
* RelationGetIndexExpressions -- get the index expressions for an index
3821
3847
*
@@ -3954,8 +3980,8 @@ RelationGetIndexPredicate(Relation relation)
3954
3980
* predicates.)
3955
3981
*
3956
3982
* Depending on attrKind, a bitmap covering the attnums for all index columns,
3957
- * for all key columns or for all the columns the configured replica identity
3958
- * are returned.
3983
+ * for all potential foreign key columns, or for all columns in the configured
3984
+ * replica identity index is returned.
3959
3985
*
3960
3986
* Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
3961
3987
* we can include system attributes (e.g., OID) in the bitmap representation.
@@ -3974,22 +4000,25 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
3974
4000
Bitmapset * uindexattrs ; /* columns in unique indexes */
3975
4001
Bitmapset * idindexattrs ; /* columns in the replica identity */
3976
4002
List * indexoidlist ;
4003
+ Oid relreplindex ;
3977
4004
ListCell * l ;
3978
4005
MemoryContext oldcxt ;
3979
4006
3980
4007
/* Quick exit if we already computed the result. */
3981
4008
if (relation -> rd_indexattr != NULL )
4009
+ {
3982
4010
switch (attrKind )
3983
4011
{
3984
- case INDEX_ATTR_BITMAP_IDENTITY_KEY :
3985
- return bms_copy (relation -> rd_idattr );
3986
- case INDEX_ATTR_BITMAP_KEY :
3987
- return bms_copy (relation -> rd_keyattr );
3988
4012
case INDEX_ATTR_BITMAP_ALL :
3989
4013
return bms_copy (relation -> rd_indexattr );
4014
+ case INDEX_ATTR_BITMAP_KEY :
4015
+ return bms_copy (relation -> rd_keyattr );
4016
+ case INDEX_ATTR_BITMAP_IDENTITY_KEY :
4017
+ return bms_copy (relation -> rd_idattr );
3990
4018
default :
3991
4019
elog (ERROR , "unknown attrKind %u" , attrKind );
3992
4020
}
4021
+ }
3993
4022
3994
4023
/* Fast path if definitely no indexes */
3995
4024
if (!RelationGetForm (relation )-> relhasindex )
@@ -4004,6 +4033,15 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
4004
4033
if (indexoidlist == NIL )
4005
4034
return NULL ;
4006
4035
4036
+ /*
4037
+ * Copy the rd_replidindex value computed by RelationGetIndexList before
4038
+ * proceeding. This is needed because a relcache flush could occur inside
4039
+ * index_open below, resetting the fields managed by RelationGetIndexList.
4040
+ * (The values we're computing will still be valid, assuming that caller
4041
+ * has a sufficient lock on the relation.)
4042
+ */
4043
+ relreplindex = relation -> rd_replidindex ;
4044
+
4007
4045
/*
4008
4046
* For each index, add referenced attributes to indexattrs.
4009
4047
*
@@ -4026,7 +4064,6 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
4026
4064
bool isKey ; /* candidate key */
4027
4065
bool isIDKey ; /* replica identity index */
4028
4066
4029
-
4030
4067
indexDesc = index_open (indexOid , AccessShareLock );
4031
4068
4032
4069
/* Extract index key information from the index's pg_index row */
@@ -4038,7 +4075,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
4038
4075
indexInfo -> ii_Predicate == NIL ;
4039
4076
4040
4077
/* Is this index the configured (or default) replica identity? */
4041
- isIDKey = indexOid == relation -> rd_replidindex ;
4078
+ isIDKey = ( indexOid == relreplindex ) ;
4042
4079
4043
4080
/* Collect simple attribute references */
4044
4081
for (i = 0 ; i < indexInfo -> ii_NumIndexAttrs ; i ++ )
@@ -4050,13 +4087,13 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
4050
4087
indexattrs = bms_add_member (indexattrs ,
4051
4088
attrnum - FirstLowInvalidHeapAttributeNumber );
4052
4089
4053
- if (isIDKey )
4054
- idindexattrs = bms_add_member (idindexattrs ,
4055
- attrnum - FirstLowInvalidHeapAttributeNumber );
4056
-
4057
4090
if (isKey )
4058
4091
uindexattrs = bms_add_member (uindexattrs ,
4059
4092
attrnum - FirstLowInvalidHeapAttributeNumber );
4093
+
4094
+ if (isIDKey )
4095
+ idindexattrs = bms_add_member (idindexattrs ,
4096
+ attrnum - FirstLowInvalidHeapAttributeNumber );
4060
4097
}
4061
4098
}
4062
4099
@@ -4071,22 +4108,28 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
4071
4108
4072
4109
list_free (indexoidlist );
4073
4110
4074
- /* Now save a copy of the bitmap in the relcache entry. */
4111
+ /*
4112
+ * Now save copies of the bitmaps in the relcache entry. We intentionally
4113
+ * set rd_indexattr last, because that's the one that signals validity of
4114
+ * the values; if we run out of memory before making that copy, we won't
4115
+ * leave the relcache entry looking like the other ones are valid but
4116
+ * empty.
4117
+ */
4075
4118
oldcxt = MemoryContextSwitchTo (CacheMemoryContext );
4076
- relation -> rd_indexattr = bms_copy (indexattrs );
4077
4119
relation -> rd_keyattr = bms_copy (uindexattrs );
4078
4120
relation -> rd_idattr = bms_copy (idindexattrs );
4121
+ relation -> rd_indexattr = bms_copy (indexattrs );
4079
4122
MemoryContextSwitchTo (oldcxt );
4080
4123
4081
4124
/* We return our original working copy for caller to play with */
4082
4125
switch (attrKind )
4083
4126
{
4084
- case INDEX_ATTR_BITMAP_IDENTITY_KEY :
4085
- return idindexattrs ;
4086
- case INDEX_ATTR_BITMAP_KEY :
4087
- return uindexattrs ;
4088
4127
case INDEX_ATTR_BITMAP_ALL :
4089
4128
return indexattrs ;
4129
+ case INDEX_ATTR_BITMAP_KEY :
4130
+ return uindexattrs ;
4131
+ case INDEX_ATTR_BITMAP_IDENTITY_KEY :
4132
+ return idindexattrs ;
4090
4133
default :
4091
4134
elog (ERROR , "unknown attrKind %u" , attrKind );
4092
4135
return NULL ;
@@ -4630,8 +4673,11 @@ load_relcache_init_file(bool shared)
4630
4673
rel -> rd_refcnt = 0 ;
4631
4674
rel -> rd_indexvalid = 0 ;
4632
4675
rel -> rd_indexlist = NIL ;
4633
- rel -> rd_indexattr = NULL ;
4634
4676
rel -> rd_oidindex = InvalidOid ;
4677
+ rel -> rd_replidindex = InvalidOid ;
4678
+ rel -> rd_indexattr = NULL ;
4679
+ rel -> rd_keyattr = NULL ;
4680
+ rel -> rd_idattr = NULL ;
4635
4681
rel -> rd_createSubid = InvalidSubTransactionId ;
4636
4682
rel -> rd_newRelfilenodeSubid = InvalidSubTransactionId ;
4637
4683
rel -> rd_amcache = NULL ;
0 commit comments