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 346c770e3fc..c735ecaa910 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -56,6 +56,7 @@ #include "catalog/storage.h" #include "commands/tablecmds.h" #include "commands/typecmds.h" +#include "common/int.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" @@ -2258,7 +2259,7 @@ StoreRelCheck(Relation rel, const char *ccname, Node *expr, static void StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal) { - int numchecks = 0; + int16 numchecks = 0; ListCell *lc; if (cooked_constraints == NIL) @@ -2282,12 +2283,18 @@ StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal) is_internal, false); 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->skip_validation, con->is_local, con->inhcount, con->is_no_inherit, is_internal); - numchecks++; + break; default: elog(ERROR, "unrecognized constraint type: %d", @@ -2342,7 +2349,7 @@ AddRelationNewConstraints(Relation rel, int numoldchecks; ParseState *pstate; ParseNamespaceItem *nsitem; - int numchecks; + int16 numchecks; List *checknames; ListCell *cell; Node *expr; @@ -2544,6 +2551,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. */ @@ -2551,8 +2568,6 @@ AddRelationNewConstraints(Relation rel, StoreRelCheck(rel, ccname, expr, cdef->initially_valid, is_local, is_local ? 0 : 1, cdef->is_no_inherit, is_internal); - numchecks++; - cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); cooked->contype = CONSTR_CHECK; cooked->conoid = constrOid; @@ -2760,6 +2775,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);