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]
/* 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. */
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 *
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);
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);
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);