diff --git a/doc/src/sgml/limits.sgml b/doc/src/sgml/limits.sgml index 7f7eb51985e..44a14947bf2 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 1c188b7a0ff..f0a159c1b77 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2331,7 +2331,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) @@ -2355,12 +2355,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: @@ -2418,7 +2424,7 @@ AddRelationNewConstraints(Relation rel, int numoldchecks; ParseState *pstate; ParseNamespaceItem *nsitem; - int numchecks; + int16 numchecks; List *checknames; List *nnnames; Node *expr; @@ -2619,6 +2625,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. */ @@ -2628,8 +2644,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; @@ -3199,6 +3213,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);