pgsql: Restructure foreign key handling code for ATTACH/DETACH

From: Álvaro Herrera <alvherre(at)alvh(dot)no-ip(dot)org>
To: pgsql-committers(at)lists(dot)postgresql(dot)org
Subject: pgsql: Restructure foreign key handling code for ATTACH/DETACH
Date: 2024-10-22 14:26:01
Message-ID: E1t3Fph-001v1n-RK@gemulon.postgresql.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-committers

Restructure foreign key handling code for ATTACH/DETACH

... to fix bugs when the referenced table is partitioned.

The catalog representation we chose for foreign keys connecting
partitioned tables (in commit f56f8f8da6af) is inconvenient, in the
sense that a standalone table has a different way to represent the
constraint when referencing a partitioned table, than when the same
table becomes a partition (and vice versa). Because of this, we need to
create additional catalog rows on detach (pg_constraint and pg_trigger),
and remove them on attach. We were doing some of those things, but not
all of them, leading to missing catalog rows in certain cases.

The worst problem seems to be that we are missing action triggers after
detaching a partition, which means that you could update/delete rows
from the referenced partitioned table that still had referencing rows on
that table, the server failing to throw the required errors.

!!!
Note that this means existing databases with FKs that reference
partitioned tables might have rows that break relational integrity, on
tables that were once partitions on the referencing side of the FK.

Another possible problem is that trying to reattach a table
that had been detached would fail indicating that internal triggers
cannot be found, which from the user's point of view is nonsensical.

In branches 15 and above, we fix this by creating a new helper function
addFkConstraint() which is in charge of creating a standalone
pg_constraint row, and repurposing addFkRecurseReferencing() and
addFkRecurseReferenced() so that they're only the recursive routine for
each side of the FK, and they call addFkConstraint() to create
pg_constraint at each partitioning level and add the necessary triggers.
These new routines can be used during partition creation, partition
attach and detach, and foreign key creation. This reduces redundant
code and simplifies the flow.

In branches 14 and 13, we have a much simpler fix that consists on
simply removing the constraint on detach. The reason is that those
branches are missing commit f4566345cf40, which reworked the way this
works in a way that we didn't consider back-patchable at the time.

We opted to leave branch 12 alone, because it's different from branch 13
enough that the fix doesn't apply; and because it is going in EOL mode
very soon, patching it now might be worse since there's no way to undo
the damage if it goes wrong.

Existing databases might need to be repaired.

In the future we might want to rethink the catalog representation to
avoid this problem, but for now the code seems to do what's required to
make the constraints operate correctly.

Co-authored-by: Jehan-Guillaume de Rorthais <jgdr(at)dalibo(dot)com>
Co-authored-by: Tender Wang <tndrwang(at)gmail(dot)com>
Co-authored-by: Alvaro Herrera <alvherre(at)alvh(dot)no-ip(dot)org>
Reported-by: Guillaume Lelarge <guillaume(at)lelarge(dot)info>
Reported-by: Jehan-Guillaume de Rorthais <jgdr(at)dalibo(dot)com>
Reported-by: Thomas Baehler (SBB CFF FFS) <thomas(dot)baehler2(at)sbb(dot)ch>
Discussion: https://postgr.es/m/20230420144344.40744130@karst
Discussion: https://postgr.es/m/20230705233028.2f554f73@karst
Discussion: https://postgr.es/m/GVAP278MB02787E7134FD691861635A8BC9032@GVAP278MB0278.CHEP278.PROD.OUTLOOK.COM
Discussion: https://postgr.es/m/18541-628a61bc267cd2d3@postgresql.org

Branch
------
REL_15_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/5d83bad6b87d0d65818ba631a254f9a74fa20601

Modified Files
--------------
src/backend/commands/tablecmds.c | 661 +++++++++++++++++++-----------
src/test/regress/expected/foreign_key.out | 96 +++++
src/test/regress/sql/foreign_key.sql | 57 +++
src/tools/pgindent/typedefs.list | 1 +
4 files changed, 565 insertions(+), 250 deletions(-)

Browse pgsql-committers by date

  From Date Subject
Next Message Fujii Masao 2024-10-22 14:58:42 pgsql: ecpg: Refactor ecpg_log() to skip unnecessary calls to ECPGget_s
Previous Message Pavel Borisov 2024-10-22 13:32:51 Re: pgsql: Implement pg_wal_replay_wait() stored procedure