1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Restrict RI fast-path FK check to btree referenced indexes

The RI fast-path check probes the referenced index directly and, for
single-column keys, uses SK_SEARCHARRAY.  Both assume the index is a
btree.  A comment claimed "PK indexes are always btree", but a foreign
key's referenced index need not be a primary key:
transformFkeyCheckAttrs() accepts any unique (or, for temporal keys,
exclusion) index, so an out-of-tree access method advertising
amcanunique could supply a non-btree index reachable by the fast path.

Add pk_index_is_btree to RI_ConstraintInfo, set from the referenced
index's access method when the constraint is loaded, and make
ri_fastpath_is_applicable() return false for non-btree indexes so such
constraints fall back to the SPI path.

Reported-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Ayush Tiwari <ayushtiwari.slg01@gmail.com>
Discussion: https://postgr.es/m/20260705210533.ee.noahmisch@microsoft.com
Backpatch-through: 19
This commit is contained in:
Amit Langote
2026-08-07 16:30:21 +09:00
parent ccfa6c9644
commit edc92e0ff9

View File

@@ -32,6 +32,7 @@
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/index.h"
#include "catalog/pg_am_d.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_namespace.h"
@@ -142,6 +143,7 @@ typedef struct RI_ConstraintInfo
Oid conindid;
bool pk_is_partitioned;
bool pk_index_is_btree; /* is conindid a btree index? */
FastPathMeta *fpmeta;
} RI_ConstraintInfo;
@@ -2503,6 +2505,8 @@ ri_LoadConstraintInfo(Oid constraintOid)
riinfo->conindid = conForm->conindid;
riinfo->pk_is_partitioned =
(get_rel_relkind(riinfo->pk_relid) == RELKIND_PARTITIONED_TABLE);
riinfo->pk_index_is_btree =
(get_rel_relam(riinfo->conindid) == BTREE_AM_OID);
ReleaseSysCache(tup);
@@ -3150,7 +3154,8 @@ ri_FastPathFlushArray(RI_FastPathEntry *fpentry, TupleTableSlot *fk_slot,
* Build scan key with SK_SEARCHARRAY. The index AM code will internally
* sort and deduplicate, then walk leaf pages in order.
*
* PK indexes are always btree, which supports SK_SEARCHARRAY.
* ri_fastpath_is_applicable() restricts the fast path to btree indexes,
* which support SK_SEARCHARRAY.
*
* This path handles single-column FKs only, so index_attnos[0] == 1.
*/
@@ -3359,6 +3364,17 @@ ri_fastpath_is_applicable(const RI_ConstraintInfo *riinfo)
if (riinfo->hasperiod)
return false;
/*
* The fast path probes the referenced index directly and, for
* single-column keys, uses SK_SEARCHARRAY. A foreign key's referenced
* index need not be a primary key; transformFkeyCheckAttrs() accepts any
* unique index, so an out-of-tree amcanunique access method could reach
* here. Restrict the fast path to btree, which is what the direct probe
* and SK_SEARCHARRAY assume; other access methods fall back to SPI.
*/
if (!riinfo->pk_index_is_btree)
return false;
return true;
}