pg.ddx.io  pgsql-committers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Álvaro Herrera <alvherre@kurilemu.de>
To: pgsql-committers@lists.postgresql.org
Subject: pgsql: Fill testing gap for possible referential integrity violation
Date: Thu, 11 Sep 2025 16:12:14 +0000
Message-ID: <E1uwju9-000D1C-2i@gemulon.postgresql.org> (raw)

Fill testing gap for possible referential integrity violation

This commit adds a missing isolation test for (non-PERIOD) foreign keys.
With REPEATABLE READ, one transaction can insert a referencing row while
another deletes the referenced row, and both see a valid state.  But
after they have committed, the table violates referential integrity.

If the INSERT precedes the DELETE, we use a crosscheck snapshot to see
the just-added row, so that the DELETE can raise a foreign key error.
You can see the table violate referential integrity if you change
ri_restrict to pass false for detectNewRows to ri_PerformCheck.

A crosscheck snapshot is not needed when the DELETE comes first, because
the INSERT's trigger takes a FOR KEY SHARE lock that sees the row now
marked for deletion, waits for that transaction to commit, and raises a
serialization error.  I (Paul) added a test for that too though.

We already have a similar test (in ri-triggers.spec) for SERIALIZABLE
snapshot isolation showing that you can implement foreign keys with just
pl/pgSQL, but that test does nothing to validate ri_triggers.c.  We also
have tests (in fk-snapshot.spec) for other concurrency scenarios, but
not this one: we test concurrently deleting both the referencing and
referenced row, when the constraint activates a cascade/set null action.
But those tests don't exercise ri_restrict, and the consequence of
omitting a crosscheck comparison is different: a serialization failure,
not a referential integrity violation.

Author: Paul Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Rustam ALLAKOV <rustamallakov@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/CA+renyUp=xja80rBaB6NpY3RRdi750y046x28bo_xg29zKY72Q@mail.gmail.com

Branch
------
master

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

Modified Files
--------------
src/test/isolation/expected/fk-snapshot-2.out | 61 +++++++++++++++++++++++++++
src/test/isolation/isolation_schedule         |  1 +
src/test/isolation/specs/fk-snapshot-2.spec   | 50 ++++++++++++++++++++++
3 files changed, 112 insertions(+)



Message-ID: <E1uwju9-000D1C-2i@gemulon.postgresql.org>
Permalink:  ../E1uwju9-000D1C-2i@gemulon.postgresql.org/
Also on:    postgresql.org/message-id/E1uwju9-000D1C-2i@gemulon.postgresql.org

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-committers@postgresql.org
  Cc: alvherre@kurilemu.de, pgsql-committers@lists.postgresql.org
  Subject: Re: pgsql: Fill testing gap for possible referential integrity violation
  In-Reply-To: <E1uwju9-000D1C-2i@gemulon.postgresql.org>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox