On Mon, Jan 29, 2024 at 8:00 AM jian he <jian.universal...@gmail.com> wrote:
>
> I fixed your tests, some of your tests can be simplified, (mainly
> primary key constraint is unnecessary for the failed tests)
> also your foreign key patch test table, temporal_rng is created at
> line 141, and we use it at around line 320.
> it's hard to get the definition of temporal_rng.  I drop the table
> and recreate it.
> So people can view the patch with tests more easily.
>
I've attached a new patch that further simplified the tests. (scope
v24 patch's 0002 and 0003)
Please ignore previous email attachments.

I've only applied the v24, 0002, 0003.
seems in doc/src/sgml/ref/create_table.sgml
lack the explanation of `<replaceable
class="parameter">temporal_interval</replaceable>`

since foreign key ON {UPDATE | DELETE} {CASCADE,SET NULL,SET DEFAULT}
not yet supported,
v24-0003 create_table.sgml should reflect that.

+ /*
+ * For FKs with PERIOD we need an operator and aggregate function
+ * to check whether the referencing row's range is contained
+ * by the aggregated ranges of the referenced row(s).
+ * For rangetypes this is fk.periodatt <@ range_agg(pk.periodatt).
+ * FKs will look these up at "runtime", but we should make sure
+ * the lookup works here.
+ */
+ if (is_temporal)
+ FindFKPeriodOpersAndProcs(opclasses[numpks - 1], &periodoperoid,
&periodprocoid);

within the function ATAddForeignKeyConstraint, you called
FindFKPeriodOpersAndProcs,
but never used the computed outputs: periodoperoid, periodprocoid,
opclasses.
We validate these(periodoperoid, periodprocoid) at
lookupTRIOperAndProc, FindFKPeriodOpersAndProcs.
I'm not sure whether FindFKPeriodOpersAndProcs in
ATAddForeignKeyConstraint is necessary.

+ * Check if all key values in OLD and NEW are "equivalent":
+ * For normal FKs we check for equality.
+ * For temporal FKs we check that the PK side is a superset of its old
value,
+ * or the FK side is a subset.
"or the FK side is a subset."  is misleading, should it be something
like "or the FK side is a subset of X"?

+ if (indexStruct->indisexclusion) return i - 1;
+ else return i;

I believe our style should be (with proper indent)
if (indexStruct->indisexclusion)
return i - 1;
else
return i;

in transformFkeyCheckAttrs
+ if (found && is_temporal)
+ {
+ found = false;
+ for (j = 0; j < numattrs + 1; j++)
+ {
+ if (periodattnum == indexStruct->indkey.values[j])
+ {
+ opclasses[numattrs] = indclass->values[j];
+ found = true;
+ break;
+ }
+ }
+ }

can be simplified:
{
found = false;
if (periodattnum == indexStruct->indkey.values[numattrs])
{
opclasses[numattrs] = indclass->values[numattrs];
found = true;
}
}

Also wondering, at the end of the function transformFkeyCheckAttrs `if
(!found)` part:
do we need another error message handle is_temporal is true?


@@ -212,8 +213,11 @@ typedef struct NewConstraint
  ConstrType contype; /* CHECK or FOREIGN */
  Oid refrelid; /* PK rel, if FOREIGN */
  Oid refindid; /* OID of PK's index, if FOREIGN */
+ bool conwithperiod; /* Whether the new FOREIGN KEY uses PERIOD */
  Oid conid; /* OID of pg_constraint entry, if FOREIGN */
  Node   *qual; /* Check expr or CONSTR_FOREIGN Constraint */
+ Oid   *operoids; /* oper oids for FOREIGN KEY with PERIOD */
+ Oid   *procoids; /* proc oids for FOREIGN KEY with PERIOD */
  ExprState  *qualstate; /* Execution state for CHECK expr */
 } NewConstraint;
primary key can only one WITHOUT OVERLAPS,
so *operoids and *procoids
can be replaced with just
`operoids, procoids`.
Also these two elements in struct NewConstraint not used in v24, 0002, 0003.
From 8ba03aa6a442d57bd0f2117e32e703fb211b68fd Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 2 Feb 2024 10:31:16 +0800
Subject: [PATCH v1 1/1] refactor temporal FOREIGN KEYs test

make related tests closer, remove unnecessary primary key constraint
so it improve test's readability
---
 .../regress/expected/without_overlaps.out     | 76 ++++++++++---------
 src/test/regress/sql/without_overlaps.sql     | 76 ++++++++++---------
 2 files changed, 82 insertions(+), 70 deletions(-)

diff --git a/src/test/regress/expected/without_overlaps.out b/src/test/regress/expected/without_overlaps.out
index c633738c..2d0f5e21 100644
--- a/src/test/regress/expected/without_overlaps.out
+++ b/src/test/regress/expected/without_overlaps.out
@@ -421,53 +421,58 @@ DROP TABLE temporal3;
 --
 -- test FOREIGN KEY, range references range
 --
+--test table setup.
+DROP TABLE IF EXISTS temporal_rng;
+CREATE TABLE temporal_rng (id int4range, valid_at tsrange);
+ALTER TABLE temporal_rng
+	ADD CONSTRAINT temporal_rng_pk
+	PRIMARY KEY (id, valid_at WITHOUT OVERLAPS);
 -- Can't create a FK with a mismatched range type
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at int4range,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk2 PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk2 FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 ERROR:  foreign key constraint "temporal_fk_rng2rng_fk2" cannot be implemented
 DETAIL:  Key columns "valid_at" and "valid_at" are of incompatible types: int4range and tsrange.
+---both referencing and referenced table's last columns specified PERIOD. shoule be ok.
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 DROP TABLE temporal_fk_rng2rng;
 -- with mismatched PERIOD columns:
 -- (parent_id, PERIOD valid_at) REFERENCES (id, valid_at)
+-- REFERENCES column part should also specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, valid_at)
 );
 ERROR:  foreign key uses PERIOD on the referencing table but not the referenced table
 -- (parent_id, valid_at) REFERENCES (id, PERIOD valid_at)
+-- foreign key last column should specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 ERROR:  foreign key uses PERIOD on the referenced table but not the referencing table
 -- (parent_id, valid_at) REFERENCES [implicit]
+-- foreign key last column should specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, valid_at)
 		REFERENCES temporal_rng
 );
@@ -477,7 +482,6 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id)
 );
@@ -487,17 +491,15 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 ERROR:  foreign key uses PERIOD on the referenced table but not the referencing table
--- with inferred PK on the referenced table:
+-- with inferred PK on the referenced table. ok
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng
 );
@@ -507,18 +509,23 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD parent_id)
 		REFERENCES temporal_rng (id, PERIOD id)
 );
 ERROR:  foreign key referenced-columns list must not contain duplicates
+DROP TABLE IF EXISTS temporal_rng2;
+CREATE TABLE temporal_rng2 (
+	id1 int4range,
+	id2 int4range,
+	valid_at tsrange,
+	CONSTRAINT temporal_rng2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS)
+);
 -- Two scalar columns
 CREATE TABLE temporal_fk2_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id1 int4range,
 	parent_id2 int4range,
-	CONSTRAINT temporal_fk2_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk2_rng2rng_fk FOREIGN KEY (parent_id1, parent_id2, PERIOD valid_at)
 		REFERENCES temporal_rng2 (id1, id2, PERIOD valid_at)
 );
@@ -526,12 +533,10 @@ CREATE TABLE temporal_fk2_rng2rng (
            Table "public.temporal_fk2_rng2rng"
    Column   |   Type    | Collation | Nullable | Default 
 ------------+-----------+-----------+----------+---------
- id         | int4range |           | not null | 
- valid_at   | tsrange   |           | not null | 
+ id         | int4range |           |          | 
+ valid_at   | tsrange   |           |          | 
  parent_id1 | int4range |           |          | 
  parent_id2 | int4range |           |          | 
-Indexes:
-    "temporal_fk2_rng2rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
 Foreign-key constraints:
     "temporal_fk2_rng2rng_fk" FOREIGN KEY (parent_id1, parent_id2, PERIOD valid_at) REFERENCES temporal_rng2(id1, id2, PERIOD valid_at)
 
@@ -601,6 +606,13 @@ ERROR:  foreign key referenced-columns list must not contain duplicates
 -- test with rows already
 --
 DELETE FROM temporal_fk_rng2rng;
+DELETE FROM temporal_rng;
+-- okay:
+INSERT INTO temporal_rng VALUES 
+('[1,1]', tsrange('2018-01-02', '2018-02-03')),
+('[1,1]', tsrange('2018-03-03', '2018-04-04')),
+('[2,2]', tsrange('2018-01-01', '2018-01-05')),
+('[3,3]', tsrange('2018-01-01', NULL));
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk;
 INSERT INTO temporal_fk_rng2rng VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]');
@@ -677,8 +689,9 @@ INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 UPDATE temporal_rng 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 temporal_rng WHERE id = '[5,5]';
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 UPDATE temporal_rng SET valid_at = tsrange('2016-02-01', '2016-03-01')
 WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
@@ -708,14 +721,15 @@ ALTER TABLE temporal_fk_rng2rng
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
 	FOREIGN KEY (parent_id, PERIOD valid_at)
 	REFERENCES temporal_rng
-	ON DELETE RESTRICT;
+	ON UPDATE RESTRICT;
 -- a PK update that succeeds because the numeric id isn't referenced:
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 UPDATE temporal_rng 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 temporal_rng WHERE id = '[5,5]';
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 UPDATE temporal_rng SET valid_at = tsrange('2016-02-01', '2016-03-01')
 WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
@@ -749,8 +763,9 @@ ALTER TABLE temporal_fk_rng2rng
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 DELETE FROM temporal_rng WHERE id = '[5,5]';
 -- a PK delete that succeeds even though the numeric id is referenced because the range isn't:
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
 -- a PK delete that fails because both are referenced:
@@ -773,8 +788,9 @@ ALTER TABLE temporal_fk_rng2rng
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 DELETE FROM temporal_rng WHERE id = '[5,5]';
 -- a PK delete that succeeds even though the numeric id is referenced because the range isn't:
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
 -- a PK delete that fails because both are referenced:
@@ -785,11 +801,9 @@ DETAIL:  Key (id, valid_at)=([5,6), ["Mon Jan 01 00:00:00 2018","Thu Feb 01 00:0
 DELETE FROM temporal_fk_rng2rng WHERE id = '[3,3]';
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01');
 --
--- test ON UPDATE/DELETE options
+-- test ON UPDATE/DELETE {set null | set default | CASCADE}
 --
 -- test FK parent updates CASCADE
-INSERT INTO temporal_rng VALUES ('[6,6]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[4,4]', tsrange('2018-01-01', '2021-01-01'), '[6,6]');
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
@@ -798,8 +812,6 @@ ALTER TABLE temporal_fk_rng2rng
 		ON DELETE CASCADE ON UPDATE CASCADE;
 ERROR:  action not supported for temporal foreign keys
 -- test FK parent updates SET NULL
-INSERT INTO temporal_rng VALUES ('[9,9]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[6,6]', tsrange('2018-01-01', '2021-01-01'), '[9,9]');
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
@@ -808,9 +820,6 @@ ALTER TABLE temporal_fk_rng2rng
 		ON DELETE SET NULL ON UPDATE SET NULL;
 ERROR:  action not supported for temporal foreign keys
 -- test FK parent updates SET DEFAULT
-INSERT INTO temporal_rng VALUES ('[-1,-1]', tsrange(null, null));
-INSERT INTO temporal_rng VALUES ('[12,12]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[8,8]', tsrange('2018-01-01', '2021-01-01'), '[12,12]');
 ALTER TABLE temporal_fk_rng2rng
   ALTER COLUMN parent_id SET DEFAULT '[-1,-1]',
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
@@ -932,7 +941,6 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE CASCADE ON UPDATE CASCADE;
 ERROR:  action not supported for temporal foreign keys
--- partitioned FK parent deletes CASCADE
 -- partitioned FK parent updates SET NULL
 ALTER TABLE temporal_partitioned_fk_rng2rng
 	DROP CONSTRAINT temporal_partitioned_fk_rng2rng_fk,
@@ -941,7 +949,6 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE SET NULL ON UPDATE SET NULL;
 ERROR:  action not supported for temporal foreign keys
--- partitioned FK parent deletes SET NULL
 -- partitioned FK parent updates SET DEFAULT
 ALTER TABLE temporal_partitioned_fk_rng2rng
   ALTER COLUMN parent_id SET DEFAULT '[-1,-1]',
@@ -951,6 +958,5 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE SET DEFAULT ON UPDATE SET DEFAULT;
 ERROR:  action not supported for temporal foreign keys
--- partitioned FK parent deletes SET DEFAULT
 DROP TABLE temporal_partitioned_fk_rng2rng;
 DROP TABLE temporal_partitioned_rng;
diff --git a/src/test/regress/sql/without_overlaps.sql b/src/test/regress/sql/without_overlaps.sql
index 641cdd5b..17bf7bdf 100644
--- a/src/test/regress/sql/without_overlaps.sql
+++ b/src/test/regress/sql/without_overlaps.sql
@@ -316,21 +316,27 @@ DROP TABLE temporal3;
 -- test FOREIGN KEY, range references range
 --
 
+--test table setup.
+DROP TABLE IF EXISTS temporal_rng;
+CREATE TABLE temporal_rng (id int4range, valid_at tsrange);
+ALTER TABLE temporal_rng
+	ADD CONSTRAINT temporal_rng_pk
+	PRIMARY KEY (id, valid_at WITHOUT OVERLAPS);
+
 -- Can't create a FK with a mismatched range type
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at int4range,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk2 PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk2 FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 
+---both referencing and referenced table's last columns specified PERIOD. shoule be ok.
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
@@ -338,29 +344,29 @@ DROP TABLE temporal_fk_rng2rng;
 
 -- with mismatched PERIOD columns:
 -- (parent_id, PERIOD valid_at) REFERENCES (id, valid_at)
+-- REFERENCES column part should also specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id, valid_at)
 );
 -- (parent_id, valid_at) REFERENCES (id, PERIOD valid_at)
+-- foreign key last column should specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, valid_at)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 -- (parent_id, valid_at) REFERENCES [implicit]
+-- foreign key last column should specify PERIOD
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, valid_at)
 		REFERENCES temporal_rng
 );
@@ -369,7 +375,6 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng (id)
 );
@@ -378,17 +383,15 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id)
 		REFERENCES temporal_rng (id, PERIOD valid_at)
 );
 
--- with inferred PK on the referenced table:
+-- with inferred PK on the referenced table. ok
 CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD valid_at)
 		REFERENCES temporal_rng
 );
@@ -399,18 +402,23 @@ CREATE TABLE temporal_fk_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id int4range,
-	CONSTRAINT temporal_fk_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk_rng2rng_fk FOREIGN KEY (parent_id, PERIOD parent_id)
 		REFERENCES temporal_rng (id, PERIOD id)
 );
 
+DROP TABLE IF EXISTS temporal_rng2;
+CREATE TABLE temporal_rng2 (
+	id1 int4range,
+	id2 int4range,
+	valid_at tsrange,
+	CONSTRAINT temporal_rng2_pk PRIMARY KEY (id1, id2, valid_at WITHOUT OVERLAPS)
+);
 -- Two scalar columns
 CREATE TABLE temporal_fk2_rng2rng (
 	id int4range,
 	valid_at tsrange,
 	parent_id1 int4range,
 	parent_id2 int4range,
-	CONSTRAINT temporal_fk2_rng2rng_pk PRIMARY KEY (id, valid_at WITHOUT OVERLAPS),
 	CONSTRAINT temporal_fk2_rng2rng_fk FOREIGN KEY (parent_id1, parent_id2, PERIOD valid_at)
 		REFERENCES temporal_rng2 (id1, id2, PERIOD valid_at)
 );
@@ -473,6 +481,14 @@ ALTER TABLE temporal_fk_rng2rng
 --
 
 DELETE FROM temporal_fk_rng2rng;
+DELETE FROM temporal_rng;
+-- okay:
+INSERT INTO temporal_rng VALUES 
+('[1,1]', tsrange('2018-01-02', '2018-02-03')),
+('[1,1]', tsrange('2018-03-03', '2018-04-04')),
+('[2,2]', tsrange('2018-01-01', '2018-01-05')),
+('[3,3]', tsrange('2018-01-01', NULL));
+
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk;
 INSERT INTO temporal_fk_rng2rng VALUES ('[1,1]', tsrange('2018-01-02', '2018-02-01'), '[1,1]');
@@ -545,8 +561,9 @@ INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 UPDATE temporal_rng 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 temporal_rng WHERE id = '[5,5]';
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 UPDATE temporal_rng SET valid_at = tsrange('2016-02-01', '2016-03-01')
 WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
@@ -574,14 +591,15 @@ ALTER TABLE temporal_fk_rng2rng
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
 	FOREIGN KEY (parent_id, PERIOD valid_at)
 	REFERENCES temporal_rng
-	ON DELETE RESTRICT;
+	ON UPDATE RESTRICT;
 -- a PK update that succeeds because the numeric id isn't referenced:
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 UPDATE temporal_rng 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 temporal_rng WHERE id = '[5,5]';
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 UPDATE temporal_rng SET valid_at = tsrange('2016-02-01', '2016-03-01')
 WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
@@ -611,8 +629,9 @@ ALTER TABLE temporal_fk_rng2rng
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 DELETE FROM temporal_rng WHERE id = '[5,5]';
 -- a PK delete that succeeds even though the numeric id is referenced because the range isn't:
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
 -- a PK delete that fails because both are referenced:
@@ -635,8 +654,9 @@ ALTER TABLE temporal_fk_rng2rng
 INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
 DELETE FROM temporal_rng WHERE id = '[5,5]';
 -- a PK delete that succeeds even though the numeric id is referenced because the range isn't:
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-01-01', '2018-02-01'));
-INSERT INTO temporal_rng VALUES ('[5,5]', tsrange('2018-02-01', '2018-03-01'));
+INSERT INTO temporal_rng VALUES 
+	('[5,5]', tsrange('2018-01-01', '2018-02-01')),
+	('[5,5]', tsrange('2018-02-01', '2018-03-01'));
 INSERT INTO temporal_fk_rng2rng VALUES ('[3,3]', tsrange('2018-01-05', '2018-01-10'), '[5,5]');
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-02-01', '2018-03-01');
 -- a PK delete that fails because both are referenced:
@@ -646,12 +666,10 @@ DELETE FROM temporal_fk_rng2rng WHERE id = '[3,3]';
 DELETE FROM temporal_rng WHERE id = '[5,5]' AND valid_at = tsrange('2018-01-01', '2018-02-01');
 
 --
--- test ON UPDATE/DELETE options
+-- test ON UPDATE/DELETE {set null | set default | CASCADE}
 --
 
 -- test FK parent updates CASCADE
-INSERT INTO temporal_rng VALUES ('[6,6]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[4,4]', tsrange('2018-01-01', '2021-01-01'), '[6,6]');
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
@@ -660,8 +678,6 @@ ALTER TABLE temporal_fk_rng2rng
 		ON DELETE CASCADE ON UPDATE CASCADE;
 
 -- test FK parent updates SET NULL
-INSERT INTO temporal_rng VALUES ('[9,9]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[6,6]', tsrange('2018-01-01', '2021-01-01'), '[9,9]');
 ALTER TABLE temporal_fk_rng2rng
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
 	ADD CONSTRAINT temporal_fk_rng2rng_fk
@@ -670,9 +686,6 @@ ALTER TABLE temporal_fk_rng2rng
 		ON DELETE SET NULL ON UPDATE SET NULL;
 
 -- test FK parent updates SET DEFAULT
-INSERT INTO temporal_rng VALUES ('[-1,-1]', tsrange(null, null));
-INSERT INTO temporal_rng VALUES ('[12,12]', tsrange('2018-01-01', '2021-01-01'));
-INSERT INTO temporal_fk_rng2rng VALUES ('[8,8]', tsrange('2018-01-01', '2021-01-01'), '[12,12]');
 ALTER TABLE temporal_fk_rng2rng
   ALTER COLUMN parent_id SET DEFAULT '[-1,-1]',
 	DROP CONSTRAINT temporal_fk_rng2rng_fk,
@@ -796,8 +809,6 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE CASCADE ON UPDATE CASCADE;
 
--- partitioned FK parent deletes CASCADE
-
 -- partitioned FK parent updates SET NULL
 
 ALTER TABLE temporal_partitioned_fk_rng2rng
@@ -807,10 +818,7 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE SET NULL ON UPDATE SET NULL;
 
--- partitioned FK parent deletes SET NULL
-
 -- partitioned FK parent updates SET DEFAULT
-
 ALTER TABLE temporal_partitioned_fk_rng2rng
   ALTER COLUMN parent_id SET DEFAULT '[-1,-1]',
 	DROP CONSTRAINT temporal_partitioned_fk_rng2rng_fk,
@@ -819,7 +827,5 @@ ALTER TABLE temporal_partitioned_fk_rng2rng
 		REFERENCES temporal_partitioned_rng
 		ON DELETE SET DEFAULT ON UPDATE SET DEFAULT;
 
--- partitioned FK parent deletes SET DEFAULT
-
 DROP TABLE temporal_partitioned_fk_rng2rng;
 DROP TABLE temporal_partitioned_rng;
-- 
2.34.1

Reply via email to