Skip to content

Commit f6cffac

Browse files
polkertyhackorum
authored andcommitted
Fix temporal foreign key validation of existing rows
NewConstraint.conwithperiod is not set correctly in three paths that queue foreign keys for ALTER TABLE phase 3 validation. This can cause ATTACH PARTITION, VALIDATE CONSTRAINT, and ALTER CONSTRAINT ... ENFORCED to validate temporal foreign keys as non-temporal. Set conwithperiod from the value already available at each site. Add regression tests for all three paths.
1 parent b597835 commit f6cffac

3 files changed

Lines changed: 178 additions & 1 deletion

File tree

src/backend/commands/tablecmds.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11233,7 +11233,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
1123311233
newcon->refrelid = RelationGetRelid(pkrel);
1123411234
newcon->refindid = indexOid;
1123511235
newcon->conid = parentConstr;
11236-
newcon->conwithperiod = fkconstraint->fk_with_period;
11236+
newcon->conwithperiod = with_period;
1123711237
newcon->qual = (Node *) fkconstraint;
1123811238

1123911239
tab->constraints = lappend(tab->constraints, newcon);
@@ -12672,6 +12672,7 @@ ATExecAlterFKConstrEnforceability(List **wqueue, ATAlterConstraint *cmdcon,
1267212672
newcon->refrelid = currcon->confrelid;
1267312673
newcon->refindid = currcon->conindid;
1267412674
newcon->conid = currcon->oid;
12675+
newcon->conwithperiod = currcon->conperiod;
1267512676
newcon->qual = (Node *) fkconstraint;
1267612677

1267712678
/* Find or create work queue entry for this table */
@@ -13560,6 +13561,7 @@ QueueFKConstraintValidation(List **wqueue, Relation conrel, Relation fkrel,
1356013561
newcon->refrelid = con->confrelid;
1356113562
newcon->refindid = con->conindid;
1356213563
newcon->conid = con->oid;
13564+
newcon->conwithperiod = con->conperiod;
1356313565
newcon->qual = (Node *) fkconstraint;
1356413566

1356513567
/* Find or create work queue entry for this table */

src/test/regress/expected/without_overlaps.out

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,4 +2698,89 @@ ERROR: unsupported ON UPDATE action for foreign key constraint using PERIOD
26982698
--
26992699
DROP TABLE temporal_partitioned_fk_mltrng2mltrng;
27002700
DROP TABLE temporal_partitioned_mltrng;
2701+
--
2702+
-- Temporal foreign key validation of existing rows
2703+
--
2704+
-- ATTACH PARTITION
2705+
CREATE TABLE temporal_attach_pk (
2706+
id int4range,
2707+
valid_at daterange,
2708+
CONSTRAINT temporal_attach_pk_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
2709+
);
2710+
INSERT INTO temporal_attach_pk VALUES ('[1,2)', daterange('2000-01-01', '2010-01-01'));
2711+
CREATE TABLE temporal_attach_fk (
2712+
id int4range,
2713+
valid_at daterange,
2714+
parent_id int4range,
2715+
CONSTRAINT temporal_attach_fk_fk FOREIGN KEY (parent_id, PERIOD valid_at)
2716+
REFERENCES temporal_attach_pk
2717+
) PARTITION BY LIST (id);
2718+
CREATE TABLE temporal_attach_fk_p1 PARTITION OF temporal_attach_fk FOR VALUES IN ('[1,2)');
2719+
CREATE TABLE temporal_attach_fk_p2 (id int4range, valid_at daterange, parent_id int4range);
2720+
INSERT INTO temporal_attach_fk_p2
2721+
VALUES ('[2,3)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2722+
-- invalid period
2723+
ALTER TABLE temporal_attach_fk ATTACH PARTITION temporal_attach_fk_p2 FOR VALUES IN ('[2,3)');
2724+
ERROR: insert or update on table "temporal_attach_fk_p2" violates foreign key constraint "temporal_attach_fk_fk"
2725+
DETAIL: Key (parent_id, valid_at)=([1,2), [2005-01-01,2020-01-01)) is not present in table "temporal_attach_pk".
2726+
-- covered period
2727+
DELETE FROM temporal_attach_fk_p2;
2728+
INSERT INTO temporal_attach_fk_p2
2729+
VALUES ('[2,3)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2730+
ALTER TABLE temporal_attach_fk ATTACH PARTITION temporal_attach_fk_p2 FOR VALUES IN ('[2,3)');
2731+
DROP TABLE temporal_attach_fk;
2732+
DROP TABLE temporal_attach_pk;
2733+
-- VALIDATE CONSTRAINT
2734+
CREATE TABLE temporal_validate_pk (
2735+
id int4range,
2736+
valid_at daterange,
2737+
CONSTRAINT temporal_validate_pk_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
2738+
);
2739+
INSERT INTO temporal_validate_pk VALUES ('[1,2)', daterange('2000-01-01', '2010-01-01'));
2740+
CREATE TABLE temporal_validate_fk (
2741+
id int4range,
2742+
valid_at daterange,
2743+
parent_id int4range
2744+
);
2745+
INSERT INTO temporal_validate_fk
2746+
VALUES ('[1,2)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2747+
ALTER TABLE temporal_validate_fk
2748+
ADD CONSTRAINT temporal_validate_fk_fk
2749+
FOREIGN KEY (parent_id, PERIOD valid_at)
2750+
REFERENCES temporal_validate_pk
2751+
NOT VALID;
2752+
-- invalid period
2753+
ALTER TABLE temporal_validate_fk VALIDATE CONSTRAINT temporal_validate_fk_fk;
2754+
ERROR: insert or update on table "temporal_validate_fk" violates foreign key constraint "temporal_validate_fk_fk"
2755+
DETAIL: Key (parent_id, valid_at)=([1,2), [2005-01-01,2020-01-01)) is not present in table "temporal_validate_pk".
2756+
-- covered period
2757+
DELETE FROM temporal_validate_fk;
2758+
INSERT INTO temporal_validate_fk
2759+
VALUES ('[1,2)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2760+
ALTER TABLE temporal_validate_fk VALIDATE CONSTRAINT temporal_validate_fk_fk;
2761+
DROP TABLE temporal_validate_fk;
2762+
-- ALTER CONSTRAINT ... ENFORCED
2763+
CREATE TABLE temporal_enforce_fk (
2764+
id int4range,
2765+
valid_at daterange,
2766+
parent_id int4range
2767+
);
2768+
INSERT INTO temporal_enforce_fk
2769+
VALUES ('[1,2)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2770+
ALTER TABLE temporal_enforce_fk
2771+
ADD CONSTRAINT temporal_enforce_fk_fk
2772+
FOREIGN KEY (parent_id, PERIOD valid_at)
2773+
REFERENCES temporal_validate_pk
2774+
NOT ENFORCED;
2775+
-- invalid period
2776+
ALTER TABLE temporal_enforce_fk ALTER CONSTRAINT temporal_enforce_fk_fk ENFORCED;
2777+
ERROR: insert or update on table "temporal_enforce_fk" violates foreign key constraint "temporal_enforce_fk_fk"
2778+
DETAIL: Key (parent_id, valid_at)=([1,2), [2005-01-01,2020-01-01)) is not present in table "temporal_validate_pk".
2779+
-- covered period
2780+
DELETE FROM temporal_enforce_fk;
2781+
INSERT INTO temporal_enforce_fk
2782+
VALUES ('[1,2)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2783+
ALTER TABLE temporal_enforce_fk ALTER CONSTRAINT temporal_enforce_fk_fk ENFORCED;
2784+
DROP TABLE temporal_enforce_fk;
2785+
DROP TABLE temporal_validate_pk;
27012786
RESET datestyle;

src/test/regress/sql/without_overlaps.sql

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,4 +2146,94 @@ ALTER TABLE temporal_partitioned_fk_mltrng2mltrng
21462146
DROP TABLE temporal_partitioned_fk_mltrng2mltrng;
21472147
DROP TABLE temporal_partitioned_mltrng;
21482148

2149+
--
2150+
-- Temporal foreign key validation of existing rows
2151+
--
2152+
2153+
-- ATTACH PARTITION
2154+
CREATE TABLE temporal_attach_pk (
2155+
id int4range,
2156+
valid_at daterange,
2157+
CONSTRAINT temporal_attach_pk_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
2158+
);
2159+
INSERT INTO temporal_attach_pk VALUES ('[1,2)', daterange('2000-01-01', '2010-01-01'));
2160+
2161+
CREATE TABLE temporal_attach_fk (
2162+
id int4range,
2163+
valid_at daterange,
2164+
parent_id int4range,
2165+
CONSTRAINT temporal_attach_fk_fk FOREIGN KEY (parent_id, PERIOD valid_at)
2166+
REFERENCES temporal_attach_pk
2167+
) PARTITION BY LIST (id);
2168+
CREATE TABLE temporal_attach_fk_p1 PARTITION OF temporal_attach_fk FOR VALUES IN ('[1,2)');
2169+
2170+
CREATE TABLE temporal_attach_fk_p2 (id int4range, valid_at daterange, parent_id int4range);
2171+
INSERT INTO temporal_attach_fk_p2
2172+
VALUES ('[2,3)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2173+
-- invalid period
2174+
ALTER TABLE temporal_attach_fk ATTACH PARTITION temporal_attach_fk_p2 FOR VALUES IN ('[2,3)');
2175+
2176+
-- covered period
2177+
DELETE FROM temporal_attach_fk_p2;
2178+
INSERT INTO temporal_attach_fk_p2
2179+
VALUES ('[2,3)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2180+
ALTER TABLE temporal_attach_fk ATTACH PARTITION temporal_attach_fk_p2 FOR VALUES IN ('[2,3)');
2181+
2182+
DROP TABLE temporal_attach_fk;
2183+
DROP TABLE temporal_attach_pk;
2184+
2185+
-- VALIDATE CONSTRAINT
2186+
CREATE TABLE temporal_validate_pk (
2187+
id int4range,
2188+
valid_at daterange,
2189+
CONSTRAINT temporal_validate_pk_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
2190+
);
2191+
INSERT INTO temporal_validate_pk VALUES ('[1,2)', daterange('2000-01-01', '2010-01-01'));
2192+
2193+
CREATE TABLE temporal_validate_fk (
2194+
id int4range,
2195+
valid_at daterange,
2196+
parent_id int4range
2197+
);
2198+
INSERT INTO temporal_validate_fk
2199+
VALUES ('[1,2)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2200+
ALTER TABLE temporal_validate_fk
2201+
ADD CONSTRAINT temporal_validate_fk_fk
2202+
FOREIGN KEY (parent_id, PERIOD valid_at)
2203+
REFERENCES temporal_validate_pk
2204+
NOT VALID;
2205+
-- invalid period
2206+
ALTER TABLE temporal_validate_fk VALIDATE CONSTRAINT temporal_validate_fk_fk;
2207+
2208+
-- covered period
2209+
DELETE FROM temporal_validate_fk;
2210+
INSERT INTO temporal_validate_fk
2211+
VALUES ('[1,2)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2212+
ALTER TABLE temporal_validate_fk VALIDATE CONSTRAINT temporal_validate_fk_fk;
2213+
DROP TABLE temporal_validate_fk;
2214+
2215+
-- ALTER CONSTRAINT ... ENFORCED
2216+
CREATE TABLE temporal_enforce_fk (
2217+
id int4range,
2218+
valid_at daterange,
2219+
parent_id int4range
2220+
);
2221+
INSERT INTO temporal_enforce_fk
2222+
VALUES ('[1,2)', daterange('2005-01-01', '2020-01-01'), '[1,2)');
2223+
ALTER TABLE temporal_enforce_fk
2224+
ADD CONSTRAINT temporal_enforce_fk_fk
2225+
FOREIGN KEY (parent_id, PERIOD valid_at)
2226+
REFERENCES temporal_validate_pk
2227+
NOT ENFORCED;
2228+
-- invalid period
2229+
ALTER TABLE temporal_enforce_fk ALTER CONSTRAINT temporal_enforce_fk_fk ENFORCED;
2230+
2231+
-- covered period
2232+
DELETE FROM temporal_enforce_fk;
2233+
INSERT INTO temporal_enforce_fk
2234+
VALUES ('[1,2)', daterange('2002-01-01', '2008-01-01'), '[1,2)');
2235+
ALTER TABLE temporal_enforce_fk ALTER CONSTRAINT temporal_enforce_fk_fk ENFORCED;
2236+
DROP TABLE temporal_enforce_fk;
2237+
DROP TABLE temporal_validate_pk;
2238+
21492239
RESET datestyle;

0 commit comments

Comments
 (0)