Fix ALTER TABLE / REPLICA IDENTITY for temporal tables
authorPeter Eisentraut <[email protected]>
Thu, 21 Nov 2024 12:50:18 +0000 (13:50 +0100)
committerPeter Eisentraut <[email protected]>
Thu, 21 Nov 2024 12:50:18 +0000 (13:50 +0100)
REPLICA IDENTITY USING INDEX did not accept a GiST index.  This should
be allowed when used as a temporal primary key.

Author: Paul Jungwirth <[email protected]>
Discussion: https://www.postgresql.org/message-id/04579cbf-b134-45e1-8f2d-8c54c849c1ee@illuminatedcomputing.com

src/backend/commands/tablecmds.c
src/test/regress/expected/without_overlaps.out
src/test/regress/sql/without_overlaps.sql

index c632d1e824589245fe6697dce4db7ee0ec307639..f53129a1c4880e05276132b14bddf0ffff5db5e6 100644 (file)
@@ -17296,9 +17296,14 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode
                 errmsg("\"%s\" is not an index for table \"%s\"",
                        RelationGetRelationName(indexRel),
                        RelationGetRelationName(rel))));
-   /* The AM must support uniqueness, and the index must in fact be unique. */
-   if (!indexRel->rd_indam->amcanunique ||
-       !indexRel->rd_index->indisunique)
+   /*
+    * The AM must support uniqueness, and the index must in fact be unique.
+    * If we have a WITHOUT OVERLAPS constraint (identified by uniqueness +
+    * exclusion), we can use that too.
+    */
+   if ((!indexRel->rd_indam->amcanunique ||
+        !indexRel->rd_index->indisunique) &&
+       !(indexRel->rd_index->indisunique && indexRel->rd_index->indisexclusion))
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot use non-unique index \"%s\" as replica identity",
index d6cb65e9a639e18fb80964b398f1f1b70b8becb9..8b5ecab6fd84cc57eaf2e0a6016b032bdaa8d903 100644 (file)
@@ -978,9 +978,25 @@ SELECT * FROM tp2 ORDER BY id, valid_at;
 
 DROP TABLE temporal_partitioned;
 -- ALTER TABLE REPLICA IDENTITY
--- (should fail)
+\d temporal_rng
+              Table "public.temporal_rng"
+  Column  |   Type    | Collation | Nullable | Default 
+----------+-----------+-----------+----------+---------
+ id       | int4range |           | not null | 
+ valid_at | daterange |           | not null | 
+Indexes:
+    "temporal_rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS)
+
 ALTER TABLE temporal_rng REPLICA IDENTITY USING INDEX temporal_rng_pk;
-ERROR:  cannot use non-unique index "temporal_rng_pk" as replica identity
+\d temporal_rng
+              Table "public.temporal_rng"
+  Column  |   Type    | Collation | Nullable | Default 
+----------+-----------+-----------+----------+---------
+ id       | int4range |           | not null | 
+ valid_at | daterange |           | not null | 
+Indexes:
+    "temporal_rng_pk" PRIMARY KEY (id, valid_at WITHOUT OVERLAPS) REPLICA IDENTITY
+
 --
 -- ON CONFLICT: ranges
 --
index 943edf3da639ef8571545ac1c9a19da72b710c0c..ce58171bc35dfc75fd906401277321e33542955b 100644 (file)
@@ -691,8 +691,9 @@ SELECT * FROM tp2 ORDER BY id, valid_at;
 DROP TABLE temporal_partitioned;
 
 -- ALTER TABLE REPLICA IDENTITY
--- (should fail)
+\d temporal_rng
 ALTER TABLE temporal_rng REPLICA IDENTITY USING INDEX temporal_rng_pk;
+\d temporal_rng
 
 --
 -- ON CONFLICT: ranges