ATTACH PARTITION: Don't match a PK with a UNIQUE constraint
authorAlvaro Herrera <[email protected]>
Mon, 15 Apr 2024 13:07:47 +0000 (15:07 +0200)
committerAlvaro Herrera <[email protected]>
Mon, 15 Apr 2024 13:07:47 +0000 (15:07 +0200)
When matching constraints in AttachPartitionEnsureIndexes() we weren't
testing the constraint type, which could make a UNIQUE key lacking a
not-null constraint incorrectly satisfy a primary key requirement.  Fix
this by testing that the constraint types match.  (Other possible
mismatches are verified by comparing index properties.)

Discussion: https://postgr.es/m/202402051447[email protected]

src/backend/commands/tablecmds.c
src/backend/utils/cache/lsyscache.c
src/include/utils/lsyscache.h
src/test/regress/expected/constraints.out
src/test/regress/sql/constraints.sql

index 78b0829ffc41922ba979ff6181f1314bcda73c37..027d68e5d2ae87a0f5542140376b35171478bc0d 100644 (file)
@@ -19550,6 +19550,11 @@ AttachPartitionEnsureIndexes(List **wqueue, Relation rel, Relation attachrel)
                    /* no dice */
                    if (!OidIsValid(cldConstrOid))
                        continue;
+
+                   /* Ensure they're both the same type of constraint */
+                   if (get_constraint_type(constraintOid) !=
+                       get_constraint_type(cldConstrOid))
+                       continue;
                }
 
                /* bingo. */
index 26368ffcc97cc7c12a28b07023757a03a91f133a..48a280d089b70d1606240dd3357ea9afeba5c918 100644 (file)
@@ -1133,6 +1133,28 @@ get_constraint_index(Oid conoid)
        return InvalidOid;
 }
 
+/*
+ * get_constraint_type
+ *     Return the pg_constraint.contype value for the given constraint.
+ *
+ * No frills.
+ */
+char
+get_constraint_type(Oid conoid)
+{
+   HeapTuple   tp;
+   char        contype;
+
+   tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
+   if (!HeapTupleIsValid(tp))
+       elog(ERROR, "cache lookup failed for constraint %u", conoid);
+
+   contype = ((Form_pg_constraint) GETSTRUCT(tp))->contype;
+   ReleaseSysCache(tp);
+
+   return contype;
+}
+
 /*             ---------- LANGUAGE CACHE ----------                     */
 
 char *
index 35a8dec2b9f3bd61746bdd0f0b24b57ec4cf4a88..20446f6f8368d58e836e41b46a118b4b534b3ae8 100644 (file)
@@ -100,6 +100,8 @@ extern char *get_collation_name(Oid colloid);
 extern bool get_collation_isdeterministic(Oid colloid);
 extern char *get_constraint_name(Oid conoid);
 extern Oid get_constraint_index(Oid conoid);
+extern char get_constraint_type(Oid conoid);
+
 extern char *get_language_name(Oid langoid, bool missing_ok);
 extern Oid get_opclass_family(Oid opclass);
 extern Oid get_opclass_input_type(Oid opclass);
index 483681ef2c6bbeded3d615f0d34d7105f352d597..51157181c640abbebe4fe9949a2b62397ebee67f 100644 (file)
@@ -1006,6 +1006,22 @@ Inherits: cnn_grandchild,
 ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey;
 ERROR:  constraint "cnn_parent_pkey" of relation "cnn_parent" does not exist
 -- keeps these tables around, for pg_upgrade testing
+-- A primary key shouldn't attach to a unique constraint
+create table cnn2_parted (a int primary key) partition by list (a);
+create table cnn2_part1 (a int unique);
+alter table cnn2_parted attach partition cnn2_part1 for values in (1);
+\d+ cnn2_part1
+                                Table "public.cnn2_part1"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a      | integer |           | not null |         | plain   |              | 
+Partition of: cnn2_parted FOR VALUES IN (1)
+Partition constraint: ((a IS NOT NULL) AND (a = 1))
+Indexes:
+    "cnn2_part1_pkey" PRIMARY KEY, btree (a)
+    "cnn2_part1_a_key" UNIQUE CONSTRAINT, btree (a)
+
+drop table cnn2_parted;
 -- ensure columns in partitions are marked not-null
 create table cnn2_parted(a int primary key) partition by list (a);
 create table cnn2_part1(a int);
index 7c95f6c2aa7c1a76786703bd0aeb01652c8f17c9..2efb63e9d8f53ebcb1e045f62890a21cdf97fbe2 100644 (file)
@@ -657,6 +657,13 @@ ALTER TABLE cnn_parent ADD PRIMARY KEY USING INDEX b_uq;
 ALTER TABLE cnn_parent DROP CONSTRAINT cnn_parent_pkey;
 -- keeps these tables around, for pg_upgrade testing
 
+-- A primary key shouldn't attach to a unique constraint
+create table cnn2_parted (a int primary key) partition by list (a);
+create table cnn2_part1 (a int unique);
+alter table cnn2_parted attach partition cnn2_part1 for values in (1);
+\d+ cnn2_part1
+drop table cnn2_parted;
+
 -- ensure columns in partitions are marked not-null
 create table cnn2_parted(a int primary key) partition by list (a);
 create table cnn2_part1(a int);