aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/tablecmds.c17
-rw-r--r--src/test/regress/expected/constraints.out42
-rw-r--r--src/test/regress/sql/constraints.sql40
3 files changed, 95 insertions, 4 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index dbfe0d6b1c1..b0bc9140138 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -19281,22 +19281,31 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
foreach(cell, indexes)
{
Oid idxid = lfirst_oid(cell);
+ Oid parentidx;
Relation idx;
Oid constrOid;
+ Oid parentConstrOid;
if (!has_superclass(idxid))
continue;
- Assert((IndexGetRelation(get_partition_parent(idxid, false), false) ==
- RelationGetRelid(rel)));
+ parentidx = get_partition_parent(idxid, false);
+ Assert((IndexGetRelation(parentidx, false) == RelationGetRelid(rel)));
idx = index_open(idxid, AccessExclusiveLock);
IndexSetParentIndex(idx, InvalidOid);
- /* If there's a constraint associated with the index, detach it too */
+ /*
+ * If there's a constraint associated with the index, detach it too.
+ * Careful: it is possible for a constraint index in a partition to be
+ * the child of a non-constraint index, so verify whether the parent
+ * index does actually have a constraint.
+ */
constrOid = get_relation_idx_constraint_oid(RelationGetRelid(partRel),
idxid);
- if (OidIsValid(constrOid))
+ parentConstrOid = get_relation_idx_constraint_oid(RelationGetRelid(rel),
+ parentidx);
+ if (OidIsValid(parentConstrOid) && OidIsValid(constrOid))
ConstraintSetParentConstraint(constrOid, InvalidOid, InvalidOid);
index_close(idx, NoLock);
diff --git a/src/test/regress/expected/constraints.out b/src/test/regress/expected/constraints.out
index e6f6602d953..03aec26657c 100644
--- a/src/test/regress/expected/constraints.out
+++ b/src/test/regress/expected/constraints.out
@@ -626,6 +626,48 @@ SELECT conname FROM pg_constraint WHERE conrelid = 'parted_fk_naming_1'::regclas
(1 row)
DROP TABLE parted_fk_naming;
+--
+-- Test various ways to create primary keys on partitions, linked to unique
+-- indexes (without constraints) on the partitioned table. Ideally these should
+-- fail, but we don't dare change released behavior, so instead cope with it at
+-- DETACH time.
+CREATE TEMP TABLE t (a integer, b integer) PARTITION BY HASH (a, b);
+CREATE TEMP TABLE tp (a integer, b integer, PRIMARY KEY (a, b), UNIQUE (b, a));
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES WITH (MODULUS 1, REMAINDER 0);
+CREATE UNIQUE INDEX t_a_idx ON t (a, b);
+CREATE UNIQUE INDEX t_b_idx ON t (b, a);
+ALTER INDEX t_a_idx ATTACH PARTITION tp_pkey;
+ALTER INDEX t_b_idx ATTACH PARTITION tp_b_a_key;
+SELECT conname, conparentid, conislocal, coninhcount
+ FROM pg_constraint WHERE conname IN ('tp_pkey', 'tp_b_a_key');
+ conname | conparentid | conislocal | coninhcount
+------------+-------------+------------+-------------
+ tp_pkey | 0 | t | 0
+ tp_b_a_key | 0 | t | 0
+(2 rows)
+
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+CREATE TEMP TABLE t (a integer) PARTITION BY LIST (a);
+CREATE TEMP TABLE tp (a integer PRIMARY KEY);
+CREATE UNIQUE INDEX t_a_idx ON t (a);
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES IN (1);
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+CREATE TEMP TABLE t (a integer) PARTITION BY LIST (a);
+CREATE TEMP TABLE tp (a integer PRIMARY KEY);
+CREATE UNIQUE INDEX t_a_idx ON ONLY t (a);
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES IN (1);
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+CREATE TABLE regress_constr_partitioned (a integer) PARTITION BY LIST (a);
+CREATE TABLE regress_constr_partition1 PARTITION OF regress_constr_partitioned FOR VALUES IN (1);
+ALTER TABLE regress_constr_partition1 ADD PRIMARY KEY (a);
+CREATE UNIQUE INDEX ON regress_constr_partitioned (a);
+BEGIN;
+ALTER TABLE regress_constr_partitioned DETACH PARTITION regress_constr_partition1;
+ROLLBACK;
+-- Leave this one in funny state for pg_upgrade testing
-- test a HOT update that invalidates the conflicting tuple.
-- the trigger should still fire and catch the violation
BEGIN;
diff --git a/src/test/regress/sql/constraints.sql b/src/test/regress/sql/constraints.sql
index 5ffcd4ffc7b..034ebf38309 100644
--- a/src/test/regress/sql/constraints.sql
+++ b/src/test/regress/sql/constraints.sql
@@ -449,6 +449,46 @@ ALTER TABLE parted_fk_naming ATTACH PARTITION parted_fk_naming_1 FOR VALUES IN (
SELECT conname FROM pg_constraint WHERE conrelid = 'parted_fk_naming_1'::regclass AND contype = 'f';
DROP TABLE parted_fk_naming;
+--
+-- Test various ways to create primary keys on partitions, linked to unique
+-- indexes (without constraints) on the partitioned table. Ideally these should
+-- fail, but we don't dare change released behavior, so instead cope with it at
+-- DETACH time.
+CREATE TEMP TABLE t (a integer, b integer) PARTITION BY HASH (a, b);
+CREATE TEMP TABLE tp (a integer, b integer, PRIMARY KEY (a, b), UNIQUE (b, a));
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES WITH (MODULUS 1, REMAINDER 0);
+CREATE UNIQUE INDEX t_a_idx ON t (a, b);
+CREATE UNIQUE INDEX t_b_idx ON t (b, a);
+ALTER INDEX t_a_idx ATTACH PARTITION tp_pkey;
+ALTER INDEX t_b_idx ATTACH PARTITION tp_b_a_key;
+SELECT conname, conparentid, conislocal, coninhcount
+ FROM pg_constraint WHERE conname IN ('tp_pkey', 'tp_b_a_key');
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+
+CREATE TEMP TABLE t (a integer) PARTITION BY LIST (a);
+CREATE TEMP TABLE tp (a integer PRIMARY KEY);
+CREATE UNIQUE INDEX t_a_idx ON t (a);
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES IN (1);
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+
+CREATE TEMP TABLE t (a integer) PARTITION BY LIST (a);
+CREATE TEMP TABLE tp (a integer PRIMARY KEY);
+CREATE UNIQUE INDEX t_a_idx ON ONLY t (a);
+ALTER TABLE t ATTACH PARTITION tp FOR VALUES IN (1);
+ALTER TABLE t DETACH PARTITION tp;
+DROP TABLE t, tp;
+
+CREATE TABLE regress_constr_partitioned (a integer) PARTITION BY LIST (a);
+CREATE TABLE regress_constr_partition1 PARTITION OF regress_constr_partitioned FOR VALUES IN (1);
+ALTER TABLE regress_constr_partition1 ADD PRIMARY KEY (a);
+CREATE UNIQUE INDEX ON regress_constr_partitioned (a);
+BEGIN;
+ALTER TABLE regress_constr_partitioned DETACH PARTITION regress_constr_partition1;
+ROLLBACK;
+-- Leave this one in funny state for pg_upgrade testing
+
-- test a HOT update that invalidates the conflicting tuple.
-- the trigger should still fire and catch the violation