diff --git c/src/backend/utils/adt/numutils.c i/src/backend/utils/adt/numutils.c index 471fbb7ee63..52bbff801d0 100644 --- c/src/backend/utils/adt/numutils.c +++ i/src/backend/utils/adt/numutils.c @@ -301,6 +301,53 @@ pg_strtoint32_safe(const char *s, Node *escontext) uint32 tmp = 0; bool neg = false; + /* + * Fast path recognizing the most common output. + */ + if (1) + { + int32 tmp_s = 0; + + /* leading spaces are uncommon => slow path */ + + /* handle - sign, + is uncommon => slow path */ + if (*ptr == '-') + { + ptr++; + neg = true; + } + + /* require at least one digit */ + if (unlikely(!isdigit((unsigned char) *ptr))) + goto slow; + + /* process digits */ + while (*ptr && isdigit((unsigned char) *ptr)) + { + int8 digit = (*ptr++ - '0'); + + if (unlikely(pg_mul_s32_overflow(tmp_s, 10, &tmp_s)) || + unlikely(pg_sub_s32_overflow(tmp_s, digit, &tmp_s))) + goto out_of_range; + } + + /* trailing spaces are uncommon => slow path */ + if (unlikely(*ptr != '\0')) + goto slow; + + if (!neg) + { + /* could fail if input is most negative number */ + if (unlikely(tmp == PG_INT32_MIN)) + goto out_of_range; + tmp = -tmp; + } + + return tmp; + } + +slow: + /* skip leading spaces */ while (likely(*ptr) && isspace((unsigned char) *ptr)) ptr++;