From 5cf152e9ffb72072e75911da7a123c1f57abd4e7 Mon Sep 17 00:00:00 2001 From: Hannu Krosing Date: Sun, 11 Jan 2026 01:04:30 +0100 Subject: [PATCH v5] rebase to current head --- src/backend/commands/tablecmds.c | 18 +++++++-- src/test/regress/expected/foreign_key.out | 35 +++++++++++++++++ src/test/regress/sql/foreign_key.sql | 46 +++++++++++++++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f976c0e5c7e..513e6df36a9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -2041,13 +2041,19 @@ ExecuteTruncateGuts(List *explicit_rels, * Check foreign key references. In CASCADE mode, this should be * unnecessary since we just pulled in all the references; but as a * cross-check, do it anyway if in an Assert-enabled build. + * + * Skip foreign key checks when `session_replication_role = replica` to + * match the behaviour of disabling FK triggers in the same situation */ + if (SessionReplicationRole != SESSION_REPLICATION_ROLE_REPLICA) + { #ifdef USE_ASSERT_CHECKING - heap_truncate_check_FKs(rels, false); -#else - if (behavior == DROP_RESTRICT) heap_truncate_check_FKs(rels, false); +#else + if (behavior == DROP_RESTRICT) + heap_truncate_check_FKs(rels, false); #endif + } /* * If we are asked to restart sequences, find all the sequences, lock them @@ -6079,7 +6085,12 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, * theoretically possible that we have changed both relations of the * foreign key, and we'd better have finished both rewrites before we try * to read the tables. + * + * Skip the check when `session_replication_mode = replica` to save time + * and to match the FK trigger behaviour in the same situation */ + if (SessionReplicationRole != SESSION_REPLICATION_ROLE_REPLICA) + { foreach(ltab, *wqueue) { AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab); @@ -6124,6 +6135,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, if (rel) table_close(rel, NoLock); } + } /* Finally, run any afterStmts that were queued up */ foreach(ltab, *wqueue) diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index 9ae4dbf1b0a..eabea671967 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -3402,6 +3402,41 @@ ALTER TABLE fk_r DROP CONSTRAINT fk_r_p_id_p_jd_fkey_1; ERROR: cannot drop inherited constraint "fk_r_p_id_p_jd_fkey_1" of relation "fk_r" ALTER TABLE fk_r_2 DROP CONSTRAINT fk_r_p_id_p_jd_fkey; ERROR: cannot drop inherited constraint "fk_r_p_id_p_jd_fkey" of relation "fk_r_2" +-- tests for SET session_replication_role = replica; +RESET session_replication_role; +-- disabling FK checks +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int REFERENCES pkt(id)); +INSERT INTO fkt VALUES(1); -- should fail +ERROR: insert or update on table "fkt" violates foreign key constraint "fkt_fk_fkey" +DETAIL: Key (fk)=(1) is not present in table "pkt". +SET session_replication_role=replica; +INSERT INTO fkt VALUES(1); -- should succeed now +DROP TABLE fkt, pkt; +RESET session_replication_role; +-- skipping FK validation during ALTER TABLE ... ADD FOREIGN KEY +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int); +INSERT INTO fkt VALUES(1); +ALTER TABLE fkt ADD FOREIGN KEY (fk) REFERENCES pkt(id); -- should fail +ERROR: insert or update on table "fkt" violates foreign key constraint "fkt_fk_fkey" +DETAIL: Key (fk)=(1) is not present in table "pkt". +SET session_replication_role=replica; +ALTER TABLE fkt ADD FOREIGN KEY (fk) REFERENCES pkt(id); -- should succeed now +DROP TABLE fkt, pkt; +RESET session_replication_role; +-- skipping FK existence checks during TRUNCATE +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int REFERENCES pkt(id)); +TRUNCATE pkt; -- should fail +ERROR: cannot truncate a table referenced in a foreign key constraint +DETAIL: Table "fkt" references "pkt". +HINT: Truncate table "fkt" at the same time, or use TRUNCATE ... CASCADE. +SET session_replication_role=replica; +TRUNCATE pkt; -- should succeed now +DROP TABLE fkt, pkt; +RESET session_replication_role; +-- end of tests for SET session_replication_role = replica; SET client_min_messages TO warning; DROP SCHEMA fkpart12 CASCADE; RESET client_min_messages; diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 3b8c95bf893..32486036304 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -2382,6 +2382,52 @@ ALTER TABLE fk_r_1 DROP CONSTRAINT fk_r_p_id_p_jd_fkey; ALTER TABLE fk_r DROP CONSTRAINT fk_r_p_id_p_jd_fkey_1; ALTER TABLE fk_r_2 DROP CONSTRAINT fk_r_p_id_p_jd_fkey; +-- tests for SET session_replication_role = replica; + +RESET session_replication_role; + +-- disabling FK checks + +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int REFERENCES pkt(id)); + +INSERT INTO fkt VALUES(1); -- should fail + +SET session_replication_role=replica; +INSERT INTO fkt VALUES(1); -- should succeed now + +DROP TABLE fkt, pkt; +RESET session_replication_role; + +-- skipping FK validation during ALTER TABLE ... ADD FOREIGN KEY + +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int); +INSERT INTO fkt VALUES(1); + +ALTER TABLE fkt ADD FOREIGN KEY (fk) REFERENCES pkt(id); -- should fail + +SET session_replication_role=replica; +ALTER TABLE fkt ADD FOREIGN KEY (fk) REFERENCES pkt(id); -- should succeed now + +DROP TABLE fkt, pkt; +RESET session_replication_role; + +-- skipping FK existence checks during TRUNCATE + +CREATE TABLE pkt(id int PRIMARY KEY); +CREATE TABLE fkt(fk int REFERENCES pkt(id)); + +TRUNCATE pkt; -- should fail + +SET session_replication_role=replica; +TRUNCATE pkt; -- should succeed now + +DROP TABLE fkt, pkt; +RESET session_replication_role; + +-- end of tests for SET session_replication_role = replica; + SET client_min_messages TO warning; DROP SCHEMA fkpart12 CASCADE; RESET client_min_messages; -- 2.43.0