From edee5634564d5f9fae4c3a10ee3182de338ed07e Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Wed, 1 Apr 2026 18:43:40 +0900 Subject: [PATCH] Make FastPathMeta self-contained by copying FmgrInfo structs FastPathMeta stored pointers into ri_compare_cache entries via compare_entries[], creating a dependency on that cache remaining stable. If ri_compare_cache entries were invalidated after fpmeta was populated, the pointers would dangle. Replace compare_entries[] with inline copies of the two FmgrInfo fields actually needed (cast_func_finfo and eq_opr_finfo), copied at populate time via fmgr_info_copy(). fpmeta now depends only on riinfo remaining valid, which is already handled by the invalidation callback. Introduced by commit 2da86c1ef9 ("Add fast path for foreign key constraint checks"), noticed while reviewing code for robustness under CLOBBER_CACHE_ALWAYS. Discussion: https://postgr.es/m/CA+HiwqFQ+ZA7hSOygv4uv_t75B3r0_gosjadetCsAEoaZwTu6g@mail.gmail.com --- src/backend/utils/adt/ri_triggers.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 52bb2f2fee9..2de08da6539 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -150,7 +150,8 @@ typedef struct RI_CompareHashEntry RI_CompareHashEntry; /* Fast-path metadata for RI checks on foreign key referencing tables */ typedef struct FastPathMeta { - RI_CompareHashEntry *compare_entries[RI_MAX_NUMKEYS]; + FmgrInfo eq_opr_finfo[RI_MAX_NUMKEYS]; + FmgrInfo cast_func_finfo[RI_MAX_NUMKEYS]; RegProcedure regops[RI_MAX_NUMKEYS]; Oid subtypes[RI_MAX_NUMKEYS]; int strats[RI_MAX_NUMKEYS]; @@ -2996,16 +2997,12 @@ build_index_scankeys(const RI_ConstraintInfo *riinfo, */ for (int i = 0; i < riinfo->nkeys; i++) { - if (pk_nulls[i] != 'n') - { - RI_CompareHashEntry *entry = fpmeta->compare_entries[i]; - - if (OidIsValid(entry->cast_func_finfo.fn_oid)) - pk_vals[i] = FunctionCall3(&entry->cast_func_finfo, - pk_vals[i], - Int32GetDatum(-1), /* typmod */ - BoolGetDatum(false)); /* implicit coercion */ - } + if (pk_nulls[i] != 'n' && + OidIsValid(fpmeta->cast_func_finfo[i].fn_oid)) + pk_vals[i] = FunctionCall3(&fpmeta->cast_func_finfo[i], + pk_vals[i], + Int32GetDatum(-1), /* typmod */ + BoolGetDatum(false)); /* implicit coercion */ } /* @@ -3048,7 +3045,10 @@ ri_populate_fastpath_metadata(RI_ConstraintInfo *riinfo, Oid lefttype; RI_CompareHashEntry *entry = ri_HashCompareOp(eq_opr, typeid); - fpmeta->compare_entries[i] = entry; + fmgr_info_copy(&fpmeta->cast_func_finfo[i], &entry->cast_func_finfo, + CurrentMemoryContext); + fmgr_info_copy(&fpmeta->eq_opr_finfo[i], &entry->eq_opr_finfo, + CurrentMemoryContext); fpmeta->regops[i] = get_opcode(eq_opr); get_op_opfamily_properties(eq_opr,