diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index d6e75ffce6..7f1bd6f75e 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -172,6 +172,7 @@ quad_poly_tbl|t radix_text_tbl|t ramp|f real_city|f +referencing_period_test|t road|t shighway|t slow_emp4000|f @@ -212,6 +213,7 @@ timetz_tbl|f tmp|f varchar_tbl|f view_base_table|t +without_overlaps_test|t -- restore normal output mode \a\t -- diff --git a/src/test/regress/expected/without_overlaps.out b/src/test/regress/expected/without_overlaps.out deleted file mode 100644 index a3c6f1ff45..0000000000 --- a/src/test/regress/expected/without_overlaps.out +++ /dev/null @@ -1,363 +0,0 @@ --- Tests for WITHOUT OVERLAPS. --- --- test input parser --- --- PK with no columns just WITHOUT OVERLAPS: -CREATE TABLE without_overlaps_test ( - valid_at tsrange, - CONSTRAINT without_overlaps_pk PRIMARY KEY (valid_at WITHOUT OVERLAPS) -); -ERROR: syntax error at or near "WITHOUT" -LINE 3: ...STRAINT without_overlaps_pk PRIMARY KEY (valid_at WITHOUT OV... - ^ --- PK with a range column that isn't there: -CREATE TABLE without_overlaps_test ( - id INTEGER, - CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ERROR: range or PERIOD "valid_at" named in WITHOUT OVERLAPS does not exist --- PK with a PERIOD that isn't there: --- PK with a non-range column: -CREATE TABLE without_overlaps_test ( - id INTEGER, - valid_at TEXT, - CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ERROR: column "valid_at" named in WITHOUT OVERLAPS is not a range type --- PK with one column plus a range: -CREATE TABLE without_overlaps_test ( - -- Since we can't depend on having btree_gist here, - -- use an int4range instead of an int. - -- (The rangetypes regression test uses the same trick.) - id int4range, - valid_at tsrange, - CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); --- PK with two columns plus a range: -CREATE TABLE without_overlaps_test2 ( - id1 int4range, - id2 int4range, - valid_at tsrange, - CONSTRAINT without_overlaps2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) -); -DROP TABLE without_overlaps_test2; --- PK with one column plus a PERIOD: --- PK with two columns plus a PERIOD: --- PK with a custom range type: -CREATE TYPE textrange2 AS range (subtype=text, collation="C"); -CREATE TABLE without_overlaps_test2 ( - id int4range, - valid_at textrange2, - CONSTRAINT without_overlaps2_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE without_overlaps_test2 DROP CONSTRAINT without_overlaps2_pk; -DROP TABLE without_overlaps_test2; -DROP TYPE textrange2; --- --- test ALTER TABLE ADD CONSTRAINT --- -DROP TABLE without_overlaps_test; -CREATE TABLE without_overlaps_test ( - id int4range, - valid_at tsrange -); -ALTER TABLE without_overlaps_test - ADD CONSTRAINT without_overlaps_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); --- --- test pg_get_constraintdef --- -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'without_overlaps_pk'; - pg_get_constraintdef ---------------------------------------------- - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -(1 row) - -DROP TABLE without_overlaps_test; -CREATE TABLE without_overlaps_test ( - id int4range, - valid_at tsrange -); -ALTER TABLE without_overlaps_test - ADD CONSTRAINT without_overlaps_pk - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); --- --- test pg_get_constraintdef --- -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'without_overlaps_pk'; - pg_get_constraintdef ---------------------------------------------- - PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -(1 row) - --- --- test PK inserts --- --- okay: -INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-03')); -INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-03-03', '2018-04-04')); -INSERT INTO without_overlaps_test VALUES ('[2,2]', tsrange('2018-01-01', '2018-01-05')); -INSERT INTO without_overlaps_test VALUES ('[3,3]', tsrange('2018-01-01', NULL)); --- should fail: -INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-01-01', '2018-01-05')); -ERROR: conflicting key value violates exclusion constraint "without_overlaps_pk" -DETAIL: Key (id, valid_at)=([1,2), ["Mon Jan 01 00:00:00 2018","Fri Jan 05 00:00:00 2018")) conflicts with existing key (id, valid_at)=([1,2), ["Tue Jan 02 00:00:00 2018","Sat Feb 03 00:00:00 2018")). -INSERT INTO without_overlaps_test VALUES (NULL, tsrange('2018-01-01', '2018-01-05')); -ERROR: null value in column "id" violates not-null constraint -DETAIL: Failing row contains (null, ["Mon Jan 01 00:00:00 2018","Fri Jan 05 00:00:00 2018")). -INSERT INTO without_overlaps_test VALUES ('[3,3]', NULL); -ERROR: null value in column "valid_at" violates not-null constraint -DETAIL: Failing row contains ([3,4), null). --- --- test changing the PK's dependencies --- -CREATE TABLE without_overlaps_test2 ( - id int4range, - valid_at tsrange, - CONSTRAINT without_overlaps2_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE without_overlaps_test2 ALTER COLUMN valid_at DROP NOT NULL; -ERROR: column "valid_at" is in a primary key -ALTER TABLE without_overlaps_test2 ALTER COLUMN valid_at TYPE tstzrange USING tstzrange(lower(valid_at), upper(valid_at)); -ALTER TABLE without_overlaps_test2 RENAME COLUMN valid_at TO valid_thru; -ALTER TABLE without_overlaps_test2 DROP COLUMN valid_thru; -DROP TABLE without_overlaps_test2; --- --- test FK parser --- -CREATE TABLE referencing_period_test ( - id int4range, - valid_at tsrange, - parent_id int4range, - CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), - CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test (id, PERIOD valid_at) -); -DROP TABLE referencing_period_test; --- with inferred PK on the referenced table: -CREATE TABLE referencing_period_test ( - id int4range, - valid_at tsrange, - parent_id int4range, - CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), - CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test -); -DROP TABLE referencing_period_test; --- should fail because of duplicate referenced columns: -CREATE TABLE referencing_period_test ( - id int4range, - valid_at tsrange, - parent_id int4range, - CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), - CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD parent_id) - REFERENCES without_overlaps_test (id, PERIOD id) -); -ERROR: foreign key referenced-columns list must not contain duplicates --- --- test ALTER TABLE ADD CONSTRAINT --- -CREATE TABLE referencing_period_test ( - id int4range, - valid_at tsrange, - parent_id int4range, - CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) -); -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test (id, PERIOD valid_at); -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; --- with inferred PK on the referenced table: -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test; --- should fail because of duplicate referenced columns: -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk2 - FOREIGN KEY (parent_id, PERIOD parent_id) - REFERENCES without_overlaps_test (id, PERIOD id); -ERROR: foreign key referenced-columns list must not contain duplicates --- --- test with rows already --- -DELETE FROM referencing_period_test; -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; -INSERT INTO referencing_period_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]'); -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test; -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; -INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); --- should fail: -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test; -ERROR: insert or update on table "referencing_period_test" violates foreign key constraint "referencing_period_fk" -DETAIL: Key (parent_id, valid_at)=([1,2), ["Tue Jan 02 00:00:00 2018","Sun Apr 01 00:00:00 2018")) is not present in table "without_overlaps_test". --- okay again: -DELETE FROM referencing_period_test; -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test; --- --- test pg_get_constraintdef --- -SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'referencing_period_fk'; - pg_get_constraintdef ------------------------------------------------------------------------------------------------- - FOREIGN KEY (parent_id, PERIOD valid_at) REFERENCES without_overlaps_test(id, PERIOD valid_at) -(1 row) - --- --- test FK child inserts --- -INSERT INTO referencing_period_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]'); --- should fail: -INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); -ERROR: insert or update on table "referencing_period_test" violates foreign key constraint "referencing_period_fk" -DETAIL: Key (parent_id, valid_at)=([1,2), ["Tue Jan 02 00:00:00 2018","Sun Apr 01 00:00:00 2018")) is not present in table "without_overlaps_test". --- now it should work: -INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-02-03', '2018-03-03')); -INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); --- --- test FK child updates --- -UPDATE referencing_period_test SET valid_at = tsrange('2018-01-02', '2018-03-01') WHERE id = '[1,1]'; --- should fail: -UPDATE referencing_period_test SET valid_at = tsrange('2018-01-02', '2018-05-01') WHERE id = '[1,1]'; -ERROR: insert or update on table "referencing_period_test" violates foreign key constraint "referencing_period_fk" -DETAIL: Key (parent_id, valid_at)=([1,2), ["Tue Jan 02 00:00:00 2018","Tue May 01 00:00:00 2018")) is not present in table "without_overlaps_test". -UPDATE referencing_period_test SET parent_id = '[8,8]' WHERE id = '[1,1]'; -ERROR: insert or update on table "referencing_period_test" violates foreign key constraint "referencing_period_fk" -DETAIL: Key (parent_id, valid_at)=([8,9), ["Tue Jan 02 00:00:00 2018","Thu Mar 01 00:00:00 2018")) is not present in table "without_overlaps_test". --- --- test FK parent updates NO ACTION --- --- a PK update that succeeds because the numeric id isn't referenced: -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') WHERE id = '[5,5]'; --- a PK update that succeeds even though the numeric id is referenced because the range isn't: -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); -INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); -UPDATE without_overlaps_test SET valid_at = tsrange('2016-02-01', '2016-03-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); --- a PK update that fails because both are referenced: -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); -ERROR: update or delete on table "without_overlaps_test" violates foreign key constraint "referencing_period_fk" on table "referencing_period_test" -DETAIL: Key (id, valid_at)=([5,6), ["Mon Jan 01 00:00:00 2018","Thu Feb 01 00:00:00 2018")) is still referenced from table "referencing_period_test". --- then delete the objecting FK record and the same PK update succeeds: -DELETE FROM referencing_period_test WHERE id = '[3,3]'; -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); --- clean up: -DELETE FROM referencing_period_test WHERE parent_id = '[5,5]'; -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; --- --- test FK parent updates RESTRICT --- -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test - ON DELETE RESTRICT; --- a PK update that succeeds because the numeric id isn't referenced: -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') WHERE id = '[5,5]'; --- a PK update that succeeds even though the numeric id is referenced because the range isn't: -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); -INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); -UPDATE without_overlaps_test SET valid_at = tsrange('2016-02-01', '2016-03-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); --- a PK update that fails because both are referenced: -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); -ERROR: update or delete on table "without_overlaps_test" violates foreign key constraint "referencing_period_fk" on table "referencing_period_test" -DETAIL: Key (id, valid_at)=([5,6), ["Mon Jan 01 00:00:00 2018","Thu Feb 01 00:00:00 2018")) is still referenced from table "referencing_period_test". --- then delete the objecting FK record and the same PK update succeeds: -DELETE FROM referencing_period_test WHERE id = '[3,3]'; -UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') - WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); --- clean up: -DELETE FROM referencing_period_test WHERE parent_id = '[5,5]'; -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; --- --- test FK parent updates CASCADE --- --- --- test FK parent updates SET NULL --- --- --- test FK parent updates SET DEFAULT --- --- --- test FK parent deletes NO ACTION --- -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test; --- a PK delete that succeeds because the numeric id isn't referenced: -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; --- a PK delete that succeeds even though the numeric id is referenced because the range isn't: -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); -INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); --- a PK delete that fails because both are referenced: -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); -ERROR: update or delete on table "without_overlaps_test" violates foreign key constraint "referencing_period_fk" on table "referencing_period_test" -DETAIL: Key (id, valid_at)=([5,6), ["Mon Jan 01 00:00:00 2018","Thu Feb 01 00:00:00 2018")) is still referenced from table "referencing_period_test". --- then delete the objecting FK record and the same PK delete succeeds: -DELETE FROM referencing_period_test WHERE id = '[3,3]'; -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); --- --- test FK parent deletes RESTRICT --- -ALTER TABLE referencing_period_test - DROP CONSTRAINT referencing_period_fk; -ALTER TABLE referencing_period_test - ADD CONSTRAINT referencing_period_fk - FOREIGN KEY (parent_id, PERIOD valid_at) - REFERENCES without_overlaps_test - ON DELETE RESTRICT; -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -DELETE FROM without_overlaps_test WHERE id = '[5,5]'; --- a PK delete that succeeds even though the numeric id is referenced because the range isn't: -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); -INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); -INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); --- a PK delete that fails because both are referenced: -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); -ERROR: update or delete on table "without_overlaps_test" violates foreign key constraint "referencing_period_fk" on table "referencing_period_test" -DETAIL: Key (id, valid_at)=([5,6), ["Mon Jan 01 00:00:00 2018","Thu Feb 01 00:00:00 2018")) is still referenced from table "referencing_period_test". --- then delete the objecting FK record and the same PK delete succeeds: -DELETE FROM referencing_period_test WHERE id = '[3,3]'; -DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); --- --- test FK parent deletes CASCADE --- --- --- test FK parent deletes SET NULL --- --- --- test FK parent deletes SET DEFAULT --- diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 8fb55f045e..39d6362aed 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -111,7 +111,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr # ---------- # Another group of parallel tests # ---------- -test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info +test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info without_overlaps # event triggers cannot run concurrently with any test that runs DDL test: event_trigger diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index a39ca1012a..cdc8e717a3 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -19,6 +19,7 @@ test: uuid test: enum test: money test: rangetypes +test: without_overlaps test: pg_lsn test: regproc test: strings diff --git a/src/test/regress/sql/without_overlaps.sql b/src/test/regress/sql/without_overlaps.sql new file mode 100644 index 0000000000..83824a55d3 --- /dev/null +++ b/src/test/regress/sql/without_overlaps.sql @@ -0,0 +1,369 @@ +-- Tests for WITHOUT OVERLAPS. + +-- +-- test input parser +-- + +-- PK with no columns just WITHOUT OVERLAPS: + +CREATE TABLE without_overlaps_test ( + valid_at tsrange, + CONSTRAINT without_overlaps_pk PRIMARY KEY (valid_at WITHOUT OVERLAPS) +); + +-- PK with a range column that isn't there: + +CREATE TABLE without_overlaps_test ( + id INTEGER, + CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); + +-- PK with a PERIOD that isn't there: +-- TODO + +-- PK with a non-range column: + +CREATE TABLE without_overlaps_test ( + id INTEGER, + valid_at TEXT, + CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); + +-- PK with one column plus a range: + +CREATE TABLE without_overlaps_test ( + -- Since we can't depend on having btree_gist here, + -- use an int4range instead of an int. + -- (The rangetypes regression test uses the same trick.) + id int4range, + valid_at tsrange, + CONSTRAINT without_overlaps_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); + +-- PK with two columns plus a range: +CREATE TABLE without_overlaps_test2 ( + id1 int4range, + id2 int4range, + valid_at tsrange, + CONSTRAINT without_overlaps2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS) +); +DROP TABLE without_overlaps_test2; + + +-- PK with one column plus a PERIOD: +-- TODO + +-- PK with two columns plus a PERIOD: +-- TODO + +-- PK with a custom range type: +CREATE TYPE textrange2 AS range (subtype=text, collation="C"); +CREATE TABLE without_overlaps_test2 ( + id int4range, + valid_at textrange2, + CONSTRAINT without_overlaps2_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); +ALTER TABLE without_overlaps_test2 DROP CONSTRAINT without_overlaps2_pk; +DROP TABLE without_overlaps_test2; +DROP TYPE textrange2; + +-- +-- test ALTER TABLE ADD CONSTRAINT +-- + +DROP TABLE without_overlaps_test; +CREATE TABLE without_overlaps_test ( + id int4range, + valid_at tsrange +); +ALTER TABLE without_overlaps_test + ADD CONSTRAINT without_overlaps_pk + PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); + +-- +-- test pg_get_constraintdef +-- + +SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'without_overlaps_pk'; + +DROP TABLE without_overlaps_test; +CREATE TABLE without_overlaps_test ( + id int4range, + valid_at tsrange +); +ALTER TABLE without_overlaps_test + ADD CONSTRAINT without_overlaps_pk + PRIMARY KEY (id, valid_at WITHOUT OVERLAPS); + +-- +-- test pg_get_constraintdef +-- + +SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'without_overlaps_pk'; + +-- +-- test PK inserts +-- + +-- okay: +INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-03')); +INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-03-03', '2018-04-04')); +INSERT INTO without_overlaps_test VALUES ('[2,2]', tsrange('2018-01-01', '2018-01-05')); +INSERT INTO without_overlaps_test VALUES ('[3,3]', tsrange('2018-01-01', NULL)); + +-- should fail: +INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-01-01', '2018-01-05')); +INSERT INTO without_overlaps_test VALUES (NULL, tsrange('2018-01-01', '2018-01-05')); +INSERT INTO without_overlaps_test VALUES ('[3,3]', NULL); + +-- +-- test changing the PK's dependencies +-- + +CREATE TABLE without_overlaps_test2 ( + id int4range, + valid_at tsrange, + CONSTRAINT without_overlaps2_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); + +ALTER TABLE without_overlaps_test2 ALTER COLUMN valid_at DROP NOT NULL; +ALTER TABLE without_overlaps_test2 ALTER COLUMN valid_at TYPE tstzrange USING tstzrange(lower(valid_at), upper(valid_at)); +ALTER TABLE without_overlaps_test2 RENAME COLUMN valid_at TO valid_thru; +ALTER TABLE without_overlaps_test2 DROP COLUMN valid_thru; +DROP TABLE without_overlaps_test2; + +-- +-- test FK parser +-- + +CREATE TABLE referencing_period_test ( + id int4range, + valid_at tsrange, + parent_id int4range, + CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), + CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test (id, PERIOD valid_at) +); +DROP TABLE referencing_period_test; + +-- with inferred PK on the referenced table: +CREATE TABLE referencing_period_test ( + id int4range, + valid_at tsrange, + parent_id int4range, + CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), + CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test +); +DROP TABLE referencing_period_test; + +-- should fail because of duplicate referenced columns: +CREATE TABLE referencing_period_test ( + id int4range, + valid_at tsrange, + parent_id int4range, + CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS), + CONSTRAINT referencing_period_fk FOREIGN KEY (parent_id, PERIOD parent_id) + REFERENCES without_overlaps_test (id, PERIOD id) +); + +-- +-- test ALTER TABLE ADD CONSTRAINT +-- + +CREATE TABLE referencing_period_test ( + id int4range, + valid_at tsrange, + parent_id int4range, + CONSTRAINT referencing_period_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) +); +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test (id, PERIOD valid_at); +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +-- with inferred PK on the referenced table: +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test; + +-- should fail because of duplicate referenced columns: +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk2 + FOREIGN KEY (parent_id, PERIOD parent_id) + REFERENCES without_overlaps_test (id, PERIOD id); + +-- +-- test with rows already +-- +DELETE FROM referencing_period_test; +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +INSERT INTO referencing_period_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]'); +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test; +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); +-- should fail: +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test; +-- okay again: +DELETE FROM referencing_period_test; +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test; + +-- +-- test pg_get_constraintdef +-- + +SELECT pg_get_constraintdef(oid) FROM pg_constraint WHERE conname = 'referencing_period_fk'; + +-- +-- test FK child inserts +-- +INSERT INTO referencing_period_test VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]'); +-- should fail: +INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); +-- now it should work: +INSERT INTO without_overlaps_test VALUES ('[1,1]', tsrange('2018-02-03', '2018-03-03')); +INSERT INTO referencing_period_test VALUES ('[2,2]', tsrange('2018-01-02', '2018-04-01'), '[1,1]'); + +-- +-- test FK child updates +-- +UPDATE referencing_period_test SET valid_at = tsrange('2018-01-02', '2018-03-01') WHERE id = '[1,1]'; +-- should fail: +UPDATE referencing_period_test SET valid_at = tsrange('2018-01-02', '2018-05-01') WHERE id = '[1,1]'; +UPDATE referencing_period_test SET parent_id = '[8,8]' WHERE id = '[1,1]'; + +-- +-- test FK parent updates NO ACTION +-- +-- a PK update that succeeds because the numeric id isn't referenced: +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') WHERE id = '[5,5]'; +-- a PK update that succeeds even though the numeric id is referenced because the range isn't: +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); +INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); +UPDATE without_overlaps_test SET valid_at = tsrange('2016-02-01', '2016-03-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); +-- a PK update that fails because both are referenced: +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- then delete the objecting FK record and the same PK update succeeds: +DELETE FROM referencing_period_test WHERE id = '[3,3]'; +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- clean up: +DELETE FROM referencing_period_test WHERE parent_id = '[5,5]'; +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +-- +-- test FK parent updates RESTRICT +-- +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test + ON DELETE RESTRICT; +-- a PK update that succeeds because the numeric id isn't referenced: +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') WHERE id = '[5,5]'; +-- a PK update that succeeds even though the numeric id is referenced because the range isn't: +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); +INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); +UPDATE without_overlaps_test SET valid_at = tsrange('2016-02-01', '2016-03-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); +-- a PK update that fails because both are referenced: +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- then delete the objecting FK record and the same PK update succeeds: +DELETE FROM referencing_period_test WHERE id = '[3,3]'; +UPDATE without_overlaps_test SET valid_at = tsrange('2016-01-01', '2016-02-01') + WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- clean up: +DELETE FROM referencing_period_test WHERE parent_id = '[5,5]'; +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +-- +-- test FK parent updates CASCADE +-- +-- TODO +-- +-- test FK parent updates SET NULL +-- +-- TODO +-- +-- test FK parent updates SET DEFAULT +-- +-- TODO + +-- +-- test FK parent deletes NO ACTION +-- +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test; +-- a PK delete that succeeds because the numeric id isn't referenced: +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +-- a PK delete that succeeds even though the numeric id is referenced because the range isn't: +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); +INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); +-- a PK delete that fails because both are referenced: +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- then delete the objecting FK record and the same PK delete succeeds: +DELETE FROM referencing_period_test WHERE id = '[3,3]'; +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- +-- test FK parent deletes RESTRICT +-- +ALTER TABLE referencing_period_test + DROP CONSTRAINT referencing_period_fk; +ALTER TABLE referencing_period_test + ADD CONSTRAINT referencing_period_fk + FOREIGN KEY (parent_id, PERIOD valid_at) + REFERENCES without_overlaps_test + ON DELETE RESTRICT; +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +DELETE FROM without_overlaps_test WHERE id = '[5,5]'; +-- a PK delete that succeeds even though the numeric id is referenced because the range isn't: +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01')); +INSERT INTO without_overlaps_test VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01')); +INSERT INTO referencing_period_test VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]'); +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01'); +-- a PK delete that fails because both are referenced: +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- then delete the objecting FK record and the same PK delete succeeds: +DELETE FROM referencing_period_test WHERE id = '[3,3]'; +DELETE FROM without_overlaps_test WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01'); +-- +-- test FK parent deletes CASCADE +-- +-- TODO +-- +-- test FK parent deletes SET NULL +-- +-- TODO +-- +-- test FK parent deletes SET DEFAULT +-- +-- TODO