From 8b003be09c64bdc565e2478a2d2c3897efd7cbdc Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Thu, 24 Sep 2026 17:02:25 +0200
Subject: [PATCH v1] Enforce the pg_class.relchecks limit

Previously, the count could overflow if sufficiently many CHECK
constraints were added to the table, which (if new CHECKs kept getting
added) could cause the table to become undroppable due to enforcement of
non-negative counts when dropping these constraints.
---
 doc/src/sgml/limits.sgml   |  7 +++++++
 src/backend/catalog/heap.c | 15 +++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/doc/src/sgml/limits.sgml b/doc/src/sgml/limits.sgml
index f26f4466719..0e9a0b4e94e 100644
--- a/doc/src/sgml/limits.sgml
+++ b/doc/src/sgml/limits.sgml
@@ -62,6 +62,13 @@
      below</entry>
     </row>
 
+    <row>
+     <entry><literal>CHECK</literal> constraints per table</entry>
+     <!-- 2^15 - 1 -->
+     <entry>32,767</entry>
+     <entry>constrained by the size of pg_class.relchecks</entry>
+    </row>
+
     <row>
      <entry>columns in a result set</entry>
      <entry>1,664</entry>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a107193d7ab..7bbf6de4f2d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2360,6 +2360,12 @@ StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
 								  con->is_local, con->inhcount,
 								  con->is_no_inherit, is_internal);
 				numchecks++;
+
+				if (numchecks > PG_INT16_MAX)
+					ereport(ERROR,
+							errmsg("too many check constraints on relation \"%s\"",
+								   RelationGetQualifiedRelationName(rel)));
+
 				break;
 
 			default:
@@ -2629,6 +2635,11 @@ AddRelationNewConstraints(Relation rel,
 
 			numchecks++;
 
+			if (numchecks > PG_INT16_MAX)
+				ereport(ERROR,
+						errmsg("too many check constraints on relation \"%s\"",
+							   RelationGetQualifiedRelationName(rel)));
+
 			cooked = palloc_object(CookedConstraint);
 			cooked->contype = CONSTR_CHECK;
 			cooked->conoid = constrOid;
@@ -3198,6 +3209,10 @@ SetRelationNumChecks(Relation rel, int numchecks)
 
 	if (relStruct->relchecks != numchecks)
 	{
+		if (numchecks > INT16_MAX || numchecks < 0)
+			elog(ERROR, "invalid new relchecks %d for relation %u",
+				 numchecks, RelationGetRelid(rel));
+
 		relStruct->relchecks = numchecks;
 
 		CatalogTupleUpdate(relrel, &reltup->t_self, reltup);
-- 
2.54.0 (Apple Git-157)

