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
+
+ CHECK constraints per table
+
+ 32,767
+ constrained by the size of pg_class.relchecks
+
+
columns in a result set
1,664
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index c85d6ef9979..cfe41b3d1d6 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2330,7 +2330,7 @@ StoreRelNotNull(Relation rel, const char *nnname, AttrNumber attnum,
static void
StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
{
- int numchecks = 0;
+ int16 numchecks = 0;
ListCell *lc;
if (cooked_constraints == NIL)
@@ -2354,12 +2354,18 @@ StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
is_internal);
break;
case CONSTR_CHECK:
+ if (pg_add_s16_overflow(numchecks, 1, &numchecks))
+ ereport(ERROR,
+ errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("too many check constraints on relation \"%s\"",
+ RelationGetRelationName(rel)));
+
con->conoid =
StoreRelCheck(rel, con->name, con->expr,
con->is_enforced, !con->skip_validation,
con->is_local, con->inhcount,
con->is_no_inherit, is_internal);
- numchecks++;
+
break;
default:
@@ -2417,7 +2423,7 @@ AddRelationNewConstraints(Relation rel,
int numoldchecks;
ParseState *pstate;
ParseNamespaceItem *nsitem;
- int numchecks;
+ int16 numchecks;
List *checknames;
List *nnnames;
Node *expr;
@@ -2618,6 +2624,16 @@ AddRelationNewConstraints(Relation rel,
checknames = lappend(checknames, ccname);
}
+ /*
+ * pg_class.relchecks stores this count in an int16, so we should
+ * avoid overflowing that field
+ */
+ if (pg_add_s16_overflow(numchecks, 1, &numchecks))
+ ereport(ERROR,
+ errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("too many check constraints on relation \"%s\"",
+ RelationGetRelationName(rel)));
+
/*
* OK, store it.
*/
@@ -2627,8 +2643,6 @@ AddRelationNewConstraints(Relation rel,
is_local ? 0 : 1, cdef->is_no_inherit,
is_internal);
- numchecks++;
-
cooked = palloc_object(CookedConstraint);
cooked->contype = CONSTR_CHECK;
cooked->conoid = constrOid;
@@ -3198,6 +3212,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);