]> granicus.if.org Git - postgresql/commitdiff
Fix duplicate primary keys in partitions
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 4 Oct 2018 14:37:20 +0000 (11:37 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 4 Oct 2018 14:40:36 +0000 (11:40 -0300)
When using the CREATE TABLE .. PARTITION OF syntax, it's possible to
cause a partition to get two primary keys if the parent already has one.
Tighten the check to disallow that.

Reported-by: Rajkumar Raghuwanshi
Author: Amul Sul
Discussion: https://postgr.es/m/CAKcux6=OnSV3-qd8Gb6W=KPPwcCz6Fe_O_MQYjTa24__Xn8XxA@mail.gmail.com

src/backend/catalog/index.c
src/test/regress/expected/indexing.out
src/test/regress/sql/indexing.sql

index 9229f619d29efa2f08b2bb91b32bb4286ce66703..39605732b16979ae70bb9972c4d8828c97027fad 100644 (file)
@@ -218,12 +218,12 @@ index_check_primary_key(Relation heapRel,
        int                     i;
 
        /*
-        * If ALTER TABLE, check that there isn't already a PRIMARY KEY. In CREATE
-        * TABLE, we have faith that the parser rejected multiple pkey clauses;
-        * and CREATE INDEX doesn't have a way to say PRIMARY KEY, so it's no
-        * problem either.
+        * If ALTER TABLE and CREATE TABLE .. PARTITION OF, check that there isn't
+        * already a PRIMARY KEY.  In CREATE TABLE for an ordinary relations, we
+        * have faith that the parser rejected multiple pkey clauses; and CREATE
+        * INDEX doesn't have a way to say PRIMARY KEY, so it's no problem either.
         */
-       if (is_alter_table &&
+       if ((is_alter_table || heapRel->rd_rel->relispartition) &&
                relationHasPrimaryKey(heapRel))
        {
                ereport(ERROR,
index 8ab543ae317639cd46016aabbc25f67334a25efd..225f4e9527401ac486ffd400cdc81cd0112c66ac 100644 (file)
@@ -800,8 +800,24 @@ Indexes:
     "idxpart_pkey" PRIMARY KEY, btree (a)
 Number of partitions: 0
 
+-- multiple primary key on child should fail
+create table failpart partition of idxpart (b primary key) for values from (0) to (100);
+ERROR:  multiple primary keys for table "failpart" are not allowed
 drop table idxpart;
--- but not if you fail to use the full partition key
+-- primary key on child is okay if there's no PK in the parent, though
+create table idxpart (a int) partition by range (a);
+create table idxpart1pk partition of idxpart (a primary key) for values from (0) to (100);
+\d idxpart1pk
+             Table "public.idxpart1pk"
+ Column |  Type   | Collation | Nullable | Default 
+--------+---------+-----------+----------+---------
+ a      | integer |           | not null | 
+Partition of: idxpart FOR VALUES FROM (0) TO (100)
+Indexes:
+    "idxpart1pk_pkey" PRIMARY KEY, btree (a)
+
+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:  insufficient columns in UNIQUE constraint definition
 DETAIL:  UNIQUE constraint on table "idxpart" lacks column "b" which is part of the partition key.
index 48b885321941e6a9e88bf508cb01b66688767375..f145384fbc9c04c69fcba57cb90396b597a0b998 100644 (file)
@@ -401,9 +401,16 @@ drop table idxpart;
 -- Verify that it works to add primary key / unique to partitioned tables
 create table idxpart (a int primary key, b int) partition by range (a);
 \d idxpart
+-- multiple primary key on child should fail
+create table failpart partition of idxpart (b primary key) for values from (0) to (100);
+drop table idxpart;
+-- primary key on child is okay if there's no PK in the parent, though
+create table idxpart (a int) partition by range (a);
+create table idxpart1pk partition of idxpart (a primary key) for values from (0) to (100);
+\d idxpart1pk
 drop table idxpart;
 
--- but not if you fail to use the full partition key
+-- Failing to use the full partition key is not allowed
 create table idxpart (a int unique, b int) partition by range (a, b);
 create table idxpart (a int, b int unique) partition by range (a, b);
 create table idxpart (a int primary key, b int) partition by range (b, a);