aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2018-10-04 11:37:20 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2018-10-04 11:40:10 -0300
commitff347f8aff04865680c19ffc818460bb2afaad5b (patch)
tree05f80cba287006196800e03cf0efd45695f5063d
parente97c4d967ba500c7ec427a56467440f036127158 (diff)
downloadpostgresql-ff347f8aff04865680c19ffc818460bb2afaad5b.tar.gz
postgresql-ff347f8aff04865680c19ffc818460bb2afaad5b.zip
Fix duplicate primary keys in partitions
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
-rw-r--r--src/backend/catalog/index.c10
-rw-r--r--src/test/regress/expected/indexing.out18
-rw-r--r--src/test/regress/sql/indexing.sql9
3 files changed, 30 insertions, 7 deletions
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 4debe6ee87a..3a24c32d145 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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,
diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out
index 8ab543ae317..225f4e95274 100644
--- a/src/test/regress/expected/indexing.out
+++ b/src/test/regress/expected/indexing.out
@@ -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.
diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql
index 48b88532194..f145384fbc9 100644
--- a/src/test/regress/sql/indexing.sql
+++ b/src/test/regress/sql/indexing.sql
@@ -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);