@@ -1901,6 +1901,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
19011901}
19021902list_free (relation -> rd_indexlist );
19031903bms_free (relation -> rd_indexattr );
1904+ bms_free (relation -> rd_keyattr );
1905+ bms_free (relation -> rd_idattr );
19041906FreeTriggerDesc (relation -> trigdesc );
19051907if (relation -> rd_options )
19061908pfree (relation -> rd_options );
@@ -2547,6 +2549,7 @@ AtEOXact_cleanup(Relation relation, bool isCommit)
25472549list_free (relation -> rd_indexlist );
25482550relation -> rd_indexlist = NIL ;
25492551relation -> rd_oidindex = InvalidOid ;
2552+ relation -> rd_replidindex = InvalidOid ;
25502553relation -> rd_indexvalid = 0 ;
25512554}
25522555}
@@ -2645,6 +2648,7 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit,
26452648list_free (relation -> rd_indexlist );
26462649relation -> rd_indexlist = NIL ;
26472650relation -> rd_oidindex = InvalidOid ;
2651+ relation -> rd_replidindex = InvalidOid ;
26482652relation -> rd_indexvalid = 0 ;
26492653}
26502654}
@@ -3596,6 +3600,10 @@ CheckConstraintFetch(Relation relation)
35963600 * of the index list. rd_oidindex is valid when rd_indexvalid isn't zero;
35973601 * it is the pg_class OID of a unique index on OID when the relation has one,
35983602 * 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.
35993607 */
36003608List *
36013609RelationGetIndexList (Relation relation )
@@ -3667,8 +3675,8 @@ RelationGetIndexList(Relation relation)
36673675
36683676/*
36693677 * Invalid, non-unique, non-immediate or predicate indexes aren't
3670- * interesting forneither oid indexesnor replication identity
3671- *indexes, so don't check them.
3678+ * interesting foreither oid indexesor replication identity indexes,
3679+ * so don't check them.
36723680 */
36733681if (!IndexIsValid (index )|| !index -> indisunique ||
36743682!index -> indimmediate ||
@@ -3681,35 +3689,29 @@ RelationGetIndexList(Relation relation)
36813689indclass -> values [0 ]== OID_BTREE_OPS_OID )
36823690oidIndex = index -> indexrelid ;
36833691
3684- /*always prefer primarykeys */
3692+ /*remember primarykey index if any */
36853693if (index -> indisprimary )
36863694pkeyIndex = index -> indexrelid ;
36873695
3688- /* explicitly chosen index */
3696+ /*remember explicitly chosen replica index */
36893697if (index -> indisreplident )
36903698candidateIndex = index -> indexrelid ;
36913699}
36923700
36933701systable_endscan (indscan );
36943702
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-
37073703heap_close (indrel ,AccessShareLock );
37083704
37093705/* Now save a copy of the completed list in the relcache entry. */
37103706oldcxt = MemoryContextSwitchTo (CacheMemoryContext );
37113707relation -> rd_indexlist = list_copy (result );
37123708relation -> 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 ;
37133715relation -> rd_indexvalid = 1 ;
37143716MemoryContextSwitchTo (oldcxt );
37153717
@@ -3767,7 +3769,8 @@ insert_ordered_oid(List *list, Oid datum)
37673769 * correctly with respect to the full index set. It is up to the caller
37683770 * to ensure that a correct rd_indexattr set has been cached before first
37693771 * 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.
37713774 */
37723775void
37733776RelationSetIndexList (Relation relation ,List * indexIds ,Oid oidIndex )
@@ -3783,6 +3786,8 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
37833786list_free (relation -> rd_indexlist );
37843787relation -> rd_indexlist = indexIds ;
37853788relation -> rd_oidindex = oidIndex ;
3789+ /* For the moment, assume the target rel hasn't got a replica index */
3790+ relation -> rd_replidindex = InvalidOid ;
37863791relation -> rd_indexvalid = 2 ;/* mark list as forced */
37873792/* Flag relation as needing eoxact cleanup (to reset the list) */
37883793EOXactListAdd (relation );
@@ -3816,6 +3821,27 @@ RelationGetOidIndex(Relation relation)
38163821return relation -> rd_oidindex ;
38173822}
38183823
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+
38193845/*
38203846 * RelationGetIndexExpressions -- get the index expressions for an index
38213847 *
@@ -3954,8 +3980,8 @@ RelationGetIndexPredicate(Relation relation)
39543980 * predicates.)
39553981 *
39563982 * Depending on attrKind, a bitmap covering the attnums for all index columns,
3957- * for all key columns or for allthe columns the configured replica identity
3958- *are returned.
3983+ * for allpotential foreign key columns, or for all columnsin the configured
3984+ *replica identity index is returned.
39593985 *
39603986 * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
39613987 * we can include system attributes (e.g., OID) in the bitmap representation.
@@ -3974,22 +4000,25 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
39744000Bitmapset * uindexattrs ;/* columns in unique indexes */
39754001Bitmapset * idindexattrs ;/* columns in the replica identity */
39764002List * indexoidlist ;
4003+ Oid relreplindex ;
39774004ListCell * l ;
39784005MemoryContext oldcxt ;
39794006
39804007/* Quick exit if we already computed the result. */
39814008if (relation -> rd_indexattr != NULL )
4009+ {
39824010switch (attrKind )
39834011{
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 );
39884012case INDEX_ATTR_BITMAP_ALL :
39894013return 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 );
39904018default :
39914019elog (ERROR ,"unknown attrKind %u" ,attrKind );
39924020}
4021+ }
39934022
39944023/* Fast path if definitely no indexes */
39954024if (!RelationGetForm (relation )-> relhasindex )
@@ -4004,6 +4033,15 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
40044033if (indexoidlist == NIL )
40054034return NULL ;
40064035
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+
40074045/*
40084046 * For each index, add referenced attributes to indexattrs.
40094047 *
@@ -4026,7 +4064,6 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
40264064bool isKey ;/* candidate key */
40274065bool isIDKey ;/* replica identity index */
40284066
4029-
40304067indexDesc = index_open (indexOid ,AccessShareLock );
40314068
40324069/* Extract index key information from the index's pg_index row */
@@ -4038,7 +4075,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
40384075indexInfo -> ii_Predicate == NIL ;
40394076
40404077/* Is this index the configured (or default) replica identity? */
4041- isIDKey = indexOid == relation -> rd_replidindex ;
4078+ isIDKey = ( indexOid == relreplindex ) ;
40424079
40434080/* Collect simple attribute references */
40444081for (i = 0 ;i < indexInfo -> ii_NumIndexAttrs ;i ++ )
@@ -4050,13 +4087,13 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
40504087indexattrs = bms_add_member (indexattrs ,
40514088attrnum - FirstLowInvalidHeapAttributeNumber );
40524089
4053- if (isIDKey )
4054- idindexattrs = bms_add_member (idindexattrs ,
4055- attrnum - FirstLowInvalidHeapAttributeNumber );
4056-
40574090if (isKey )
40584091uindexattrs = bms_add_member (uindexattrs ,
40594092attrnum - FirstLowInvalidHeapAttributeNumber );
4093+
4094+ if (isIDKey )
4095+ idindexattrs = bms_add_member (idindexattrs ,
4096+ attrnum - FirstLowInvalidHeapAttributeNumber );
40604097}
40614098}
40624099
@@ -4071,22 +4108,28 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
40714108
40724109list_free (indexoidlist );
40734110
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+ */
40754118oldcxt = MemoryContextSwitchTo (CacheMemoryContext );
4076- relation -> rd_indexattr = bms_copy (indexattrs );
40774119relation -> rd_keyattr = bms_copy (uindexattrs );
40784120relation -> rd_idattr = bms_copy (idindexattrs );
4121+ relation -> rd_indexattr = bms_copy (indexattrs );
40794122MemoryContextSwitchTo (oldcxt );
40804123
40814124/* We return our original working copy for caller to play with */
40824125switch (attrKind )
40834126{
4084- case INDEX_ATTR_BITMAP_IDENTITY_KEY :
4085- return idindexattrs ;
4086- case INDEX_ATTR_BITMAP_KEY :
4087- return uindexattrs ;
40884127case INDEX_ATTR_BITMAP_ALL :
40894128return indexattrs ;
4129+ case INDEX_ATTR_BITMAP_KEY :
4130+ return uindexattrs ;
4131+ case INDEX_ATTR_BITMAP_IDENTITY_KEY :
4132+ return idindexattrs ;
40904133default :
40914134elog (ERROR ,"unknown attrKind %u" ,attrKind );
40924135return NULL ;
@@ -4630,8 +4673,11 @@ load_relcache_init_file(bool shared)
46304673rel -> rd_refcnt = 0 ;
46314674rel -> rd_indexvalid = 0 ;
46324675rel -> rd_indexlist = NIL ;
4633- rel -> rd_indexattr = NULL ;
46344676rel -> rd_oidindex = InvalidOid ;
4677+ rel -> rd_replidindex = InvalidOid ;
4678+ rel -> rd_indexattr = NULL ;
4679+ rel -> rd_keyattr = NULL ;
4680+ rel -> rd_idattr = NULL ;
46354681rel -> rd_createSubid = InvalidSubTransactionId ;
46364682rel -> rd_newRelfilenodeSubid = InvalidSubTransactionId ;
46374683rel -> rd_amcache = NULL ;