mirror of
https://github.com/postgres/postgres.git
synced 2025-11-03 09:13:20 +03:00
Fix NO ACTION temporal foreign keys when the referenced endpoints change
If a referenced UPDATE changes the temporal start/end times, shrinking the span the row is valid, we get a false return from ri_Check_Pk_Match(), but overlapping references may still be valid, if their reference didn't overlap with the removed span. We need to consider what span(s) are still provided in the referenced table. Instead of returning that from ri_Check_Pk_Match(), we can just look it up in the main SQL query. Reported-by: Sam Gabrielsson <sam@movsom.se> Author: Paul Jungwirth <pj@illuminatedcomputing.com> Discussion: https://www.postgresql.org/message-id/flat/CA+renyUApHgSZF9-nd-a0+OPGharLQLO=mDHcY4_qQ0+noCUVg@mail.gmail.com
This commit is contained in:
@@ -1249,6 +1249,33 @@ UPDATE temporal_rng
|
||||
SET valid_at = CASE WHEN lower(valid_at) = '2018-01-01' THEN daterange('2018-01-01', '2018-01-05')
|
||||
WHEN lower(valid_at) = '2018-02-01' THEN daterange('2018-01-05', '2018-03-01') END
|
||||
WHERE id = '[6,7)';
|
||||
-- a PK update shrinking the referenced range but still valid:
|
||||
-- There are two references: one fulfilled by the first pk row,
|
||||
-- the other fulfilled by both pk rows combined.
|
||||
INSERT INTO temporal_rng (id, valid_at) VALUES
|
||||
('[1,2)', daterange('2018-01-01', '2018-03-01')),
|
||||
('[1,2)', daterange('2018-03-01', '2018-06-01'));
|
||||
INSERT INTO temporal_fk_rng2rng (id, valid_at, parent_id) VALUES
|
||||
('[1,2)', daterange('2018-01-15', '2018-02-01'), '[1,2)'),
|
||||
('[2,3)', daterange('2018-01-15', '2018-05-01'), '[1,2)');
|
||||
UPDATE temporal_rng SET valid_at = daterange('2018-01-15', '2018-03-01')
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update growing the referenced range is fine:
|
||||
UPDATE temporal_rng SET valid_at = daterange('2018-01-01', '2018-03-01')
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-25'::date;
|
||||
-- a PK update shrinking the referenced range and changing the id invalidates the whole range (error):
|
||||
UPDATE temporal_rng SET id = '[2,3)', valid_at = daterange('2018-01-15', '2018-03-01')
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update changing only the id invalidates the whole range (error):
|
||||
UPDATE temporal_rng SET id = '[2,3)'
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update that loses time from both ends, but is still valid:
|
||||
INSERT INTO temporal_rng (id, valid_at) VALUES
|
||||
('[2,3)', daterange('2018-01-01', '2018-03-01'));
|
||||
INSERT INTO temporal_fk_rng2rng (id, valid_at, parent_id) VALUES
|
||||
('[5,6)', daterange('2018-01-15', '2018-02-01'), '[2,3)');
|
||||
UPDATE temporal_rng SET valid_at = daterange('2018-01-15', '2018-02-15')
|
||||
WHERE id = '[2,3)';
|
||||
-- a PK update that fails because both are referenced:
|
||||
UPDATE temporal_rng SET valid_at = daterange('2016-01-01', '2016-02-01')
|
||||
WHERE id = '[5,6)' AND valid_at = daterange('2018-01-01', '2018-02-01');
|
||||
@@ -1710,6 +1737,33 @@ UPDATE temporal_mltrng
|
||||
SET valid_at = CASE WHEN lower(valid_at) = '2018-01-01' THEN datemultirange(daterange('2018-01-01', '2018-01-05'))
|
||||
WHEN lower(valid_at) = '2018-02-01' THEN datemultirange(daterange('2018-01-05', '2018-03-01')) END
|
||||
WHERE id = '[6,7)';
|
||||
-- a PK update shrinking the referenced multirange but still valid:
|
||||
-- There are two references: one fulfilled by the first pk row,
|
||||
-- the other fulfilled by both pk rows combined.
|
||||
INSERT INTO temporal_mltrng (id, valid_at) VALUES
|
||||
('[1,2)', datemultirange(daterange('2018-01-01', '2018-03-01'))),
|
||||
('[1,2)', datemultirange(daterange('2018-03-01', '2018-06-01')));
|
||||
INSERT INTO temporal_fk_mltrng2mltrng (id, valid_at, parent_id) VALUES
|
||||
('[1,2)', datemultirange(daterange('2018-01-15', '2018-02-01')), '[1,2)'),
|
||||
('[2,3)', datemultirange(daterange('2018-01-15', '2018-05-01')), '[1,2)');
|
||||
UPDATE temporal_mltrng SET valid_at = datemultirange(daterange('2018-01-15', '2018-03-01'))
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update growing the referenced multirange is fine:
|
||||
UPDATE temporal_mltrng SET valid_at = datemultirange(daterange('2018-01-01', '2018-03-01'))
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-25'::date;
|
||||
-- a PK update shrinking the referenced multirange and changing the id invalidates the whole multirange (error):
|
||||
UPDATE temporal_mltrng SET id = '[2,3)', valid_at = datemultirange(daterange('2018-01-15', '2018-03-01'))
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update changing only the id invalidates the whole multirange (error):
|
||||
UPDATE temporal_mltrng SET id = '[2,3)'
|
||||
WHERE id = '[1,2)' AND valid_at @> '2018-01-15'::date;
|
||||
-- a PK update that loses time from both ends, but is still valid:
|
||||
INSERT INTO temporal_mltrng (id, valid_at) VALUES
|
||||
('[2,3)', datemultirange(daterange('2018-01-01', '2018-03-01')));
|
||||
INSERT INTO temporal_fk_mltrng2mltrng (id, valid_at, parent_id) VALUES
|
||||
('[5,6)', datemultirange(daterange('2018-01-15', '2018-02-01')), '[2,3)');
|
||||
UPDATE temporal_mltrng SET valid_at = datemultirange(daterange('2018-01-15', '2018-02-15'))
|
||||
WHERE id = '[2,3)';
|
||||
-- a PK update that fails because both are referenced:
|
||||
UPDATE temporal_mltrng SET valid_at = datemultirange(daterange('2016-01-01', '2016-02-01'))
|
||||
WHERE id = '[5,6)' AND valid_at = datemultirange(daterange('2018-01-01', '2018-02-01'));
|
||||
|
||||
Reference in New Issue
Block a user