Improve "constraint must include all partitioning columns" message.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 9 Jan 2026 17:59:35 +0000 (12:59 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 9 Jan 2026 17:59:35 +0000 (12:59 -0500)
This formerly said "unique constraint must ...", which was accurate
enough when it only applied to UNIQUE and PRIMARY KEY constraints.
However, now we use it for exclusion constraints too, and in that
case it's a tad confusing.  Do what we already did in the errdetail
message: print the constraint_type, so that it looks like "UNIQUE
constraint ...", "EXCLUDE constraint ...", etc.

Author: jian he <jian.universality@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CACJufxH6VhAf65Vghg4T2q315gY=Rt4BUfMyunkfRj0n2S9n-g@mail.gmail.com

src/backend/commands/indexcmds.c
src/test/regress/expected/indexing.out

index 08c86cc163c6a2c083d16dee6e4904593ec38514..635679cc1f207035bf3b78caa99812117427b21a 100644 (file)
@@ -1093,7 +1093,10 @@ DefineIndex(ParseState *pstate,
                                                                        key->partattrs[i] - 1);
                                ereport(ERROR,
                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                errmsg("unique constraint on partitioned table must include all partitioning columns"),
+                               /* translator: %s is UNIQUE, PRIMARY KEY, etc */
+                                                errmsg("%s constraint on partitioned table must include all partitioning columns",
+                                                               constraint_type),
+                               /* translator: first %s is UNIQUE, PRIMARY KEY, etc */
                                                 errdetail("%s constraint on table \"%s\" lacks column \"%s\" which is part of the partition key.",
                                                                   constraint_type, RelationGetRelationName(rel),
                                                                   NameStr(att->attname))));
index 4d29fb85293e0a657b3e4ac79649c162d0868d5a..dc629928c8fa9027d9bbf0524a0ab25b0f486656 100644 (file)
@@ -972,16 +972,16 @@ Indexes:
 drop table idxpart;
 -- Failing to use the full partition key is not allowed
 create table idxpart (a int unique, b int) partition by range (a, b);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  UNIQUE constraint on partitioned table must include all partitioning columns
 DETAIL:  UNIQUE constraint on table "idxpart" lacks column "b" which is part of the partition key.
 create table idxpart (a int, b int unique) partition by range (a, b);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  UNIQUE constraint on partitioned table must include all partitioning columns
 DETAIL:  UNIQUE constraint on table "idxpart" lacks column "a" which is part of the partition key.
 create table idxpart (a int primary key, b int) partition by range (b, a);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  PRIMARY KEY constraint on partitioned table must include all partitioning columns
 DETAIL:  PRIMARY KEY constraint on table "idxpart" lacks column "b" which is part of the partition key.
 create table idxpart (a int, b int primary key) partition by range (b, a);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  PRIMARY KEY constraint on partitioned table must include all partitioning columns
 DETAIL:  PRIMARY KEY constraint on table "idxpart" lacks column "a" which is part of the partition key.
 -- OK if you use them in some other order
 create table idxpart (a int, b int, c text, primary key  (a, b, c)) partition by range (b, c, a);
@@ -997,7 +997,7 @@ create table idxpart (a int4range, b int4range, exclude USING GIST (a with =, b
 drop table idxpart;
 -- Not OK more than one equal column: partition keys are a proper superset of constraint
 create table idxpart (a int4range, b int4range, exclude USING GIST (a with = )) partition by range (a, b);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  EXCLUDE constraint on partitioned table must include all partitioning columns
 DETAIL:  EXCLUDE constraint on table "idxpart" lacks column "b" which is part of the partition key.
 -- Not OK with just -|-
 create table idxpart (a int4range, exclude USING GIST (a with -|- )) partition by range (a);
@@ -1007,7 +1007,7 @@ create table idxpart (a int4range, b int4range, exclude USING GIST (a with =, b
 drop table idxpart;
 -- Not OK with equals and &&, and equals is not the partition key
 create table idxpart (a int4range, b int4range, c int4range, exclude USING GIST (b with =, c with &&)) partition by range (a);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  EXCLUDE constraint on partitioned table must include all partitioning columns
 DETAIL:  EXCLUDE constraint on table "idxpart" lacks column "a" which is part of the partition key.
 -- OK more than one equal column and a && column
 create table idxpart (a int4range, b int4range, c int4range, exclude USING GIST (a with =, b with =, c with &&)) partition by range (a, b);
@@ -1022,7 +1022,7 @@ DETAIL:  UNIQUE constraints cannot be used when partition keys include expressio
 -- use ALTER TABLE to add a primary key
 create table idxpart (a int, b int, c text) partition by range (a, b);
 alter table idxpart add primary key (a);       -- not an incomplete one though
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  PRIMARY KEY constraint on partitioned table must include all partitioning columns
 DETAIL:  PRIMARY KEY constraint on table "idxpart" lacks column "b" which is part of the partition key.
 alter table idxpart add primary key (a, b);    -- this works
 \d idxpart
@@ -1053,7 +1053,7 @@ drop table idxpart;
 -- use ALTER TABLE to add a unique constraint
 create table idxpart (a int, b int) partition by range (a, b);
 alter table idxpart add unique (a);                    -- not an incomplete one though
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  UNIQUE constraint on partitioned table must include all partitioning columns
 DETAIL:  UNIQUE constraint on table "idxpart" lacks column "b" which is part of the partition key.
 alter table idxpart add unique (b, a);         -- this works
 \d idxpart
@@ -1083,7 +1083,7 @@ drop table idxpart;
 -- Not OK more than one equal column: partition keys are a proper superset of constraint
 create table idxpart (a int4range, b int4range) partition by range (a, b);
 alter table idxpart add exclude USING GIST (a with =);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  EXCLUDE constraint on partitioned table must include all partitioning columns
 DETAIL:  EXCLUDE constraint on table "idxpart" lacks column "b" which is part of the partition key.
 drop table idxpart;
 -- Not OK with just -|-
@@ -1098,7 +1098,7 @@ drop table idxpart;
 -- Not OK with equals and &&, and equals is not the partition key
 create table idxpart (a int4range, b int4range, c int4range) partition by range (a);
 alter table idxpart add exclude USING GIST (b with =, c with &&);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  EXCLUDE constraint on partitioned table must include all partitioning columns
 DETAIL:  EXCLUDE constraint on table "idxpart" lacks column "a" which is part of the partition key.
 drop table idxpart;
 -- OK more than one equal column and a && column
@@ -1145,7 +1145,7 @@ drop table idxpart;
 create table idxpart (a int, b int, primary key (a)) partition by range (a);
 create table idxpart2 partition of idxpart
 for values from (0) to (1000) partition by range (b); -- fail
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  PRIMARY KEY constraint on partitioned table must include all partitioning columns
 DETAIL:  PRIMARY KEY constraint on table "idxpart2" lacks column "b" which is part of the partition key.
 drop table idxpart;
 -- Ditto for the ATTACH PARTITION case
@@ -1153,7 +1153,7 @@ create table idxpart (a int unique, b int) partition by range (a);
 create table idxpart1 (a int not null, b int, unique (a, b))
   partition by range (a, b);
 alter table idxpart attach partition idxpart1 for values from (1) to (1000);
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  UNIQUE constraint on partitioned table must include all partitioning columns
 DETAIL:  UNIQUE constraint on table "idxpart1" lacks column "b" which is part of the partition key.
 DROP TABLE idxpart, idxpart1;
 -- Multi-layer partitioning works correctly in this case:
@@ -1448,7 +1448,7 @@ insert into covidxpart values (4, 1);
 ERROR:  duplicate key value violates unique constraint "covidxpart4_a_b_idx"
 DETAIL:  Key (a)=(4) already exists.
 create unique index on covidxpart (b) include (a); -- should fail
-ERROR:  unique constraint on partitioned table must include all partitioning columns
+ERROR:  UNIQUE constraint on partitioned table must include all partitioning columns
 DETAIL:  UNIQUE constraint on table "covidxpart" lacks column "a" which is part of the partition key.
 -- check that detaching a partition also detaches the primary key constraint
 create table parted_pk_detach_test (a int primary key) partition by list (a);