Handle nullable referenced key in RI fast-path check

The RI fast-path FK check asserted that the referenced key is never
NULL, in ri_FastPathFlushArray() and in recheck_matched_pk_tuple().
That holds for a primary key, but a foreign key may reference any
unique column, and a UNIQUE column is nullable.

The assertion is reachable under READ COMMITTED.  ri_LockPKTuple()
locks the matched PK tuple with TUPLE_LOCK_FLAG_FIND_LAST_VERSION, so
when a concurrent transaction commits a key-changing UPDATE while the
check waits, the lock follows the update chain to the latest version.
If that version now has NULL in the referenced column, the fast path
reaches the assert; in a non-assert build it would compare against the
NULL and treat it as a match.

A NULL referenced key cannot equal any (non-null) FK value, so treat it
as no match and let the ordinary foreign-key violation be raised.  This
matches the SPI path, whose requalifying "pkatt = $n" evaluates to NULL
for such a row, so the row is not returned and the check reports a
violation.

Reported-by: Noah Misch <[email protected]>
Reviewed-by: Ayush Tiwari <[email protected]>
Discussion: https://postgr.es/m/[email protected]
Backpatch-through: 19

Branch
------
REL_19_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/a05ece57b16088e564bf95f92646350bafa2cfa1

Modified Files
--------------
src/backend/utils/adt/ri_triggers.c                | 25 +++++++++++---
.../isolation/expected/fk-fastpath-null-key.out    | 17 +++++++++
src/test/isolation/isolation_schedule              |  1 +
src/test/isolation/specs/fk-fastpath-null-key.spec | 40 ++++++++++++++++++++++
4 files changed, 78 insertions(+), 5 deletions(-)

Reply via email to