From: Heikki Linnakangas Date: Fri, 21 Nov 2025 13:03:11 +0000 (+0200) Subject: Use strtoi64() in pgbench, replacing its open-coded implementation X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=HEAD;p=postgresql.git Use strtoi64() in pgbench, replacing its open-coded implementation Makes the code a little simpler. The old implementation accepted trailing whitespace, but that was unnecessary. Firstly, its sibling function for parsing decimals, strtodouble(), does not accept trailing whitespace. Secondly, none of the callers can pass a string with trailing whitespace to it. In the passing, check specifically for ERANGE before printing the "out of range" error. On some systems, strtoul() and strtod() return EINVAL on an empty or all-spaces string, and "invalid input syntax" is more appropriate for that than "out of range". For the existing strtodouble() function this is purely academical because it's never called with errorOK==false, but let's be tidy. (Perhaps we should remove the dead codepaths altogether, but I'll leave that for another day.) Reviewed-by: Chao Li Reviewed-by: Yuefei Shi Reviewed-by: Neil Chen Discussion: https://www.postgresql.org/message-id/861dd5bd-f2c9-4ff5-8aa0-f82bdb75ec1f@iki.fi --- diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index a425176ecdc..68774a59efd 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -982,13 +982,17 @@ usage(void) progname, progname, PACKAGE_BUGREPORT, PACKAGE_NAME, PACKAGE_URL); } -/* return whether str matches "^\s*[-+]?[0-9]+$" */ +/* + * Return whether str matches "^\s*[-+]?[0-9]+$" + * + * This should agree with strtoint64() on what's accepted, ignoring overflows. + */ static bool is_an_int(const char *str) { const char *ptr = str; - /* skip leading spaces; cast is consistent with strtoint64 */ + /* skip leading spaces */ while (*ptr && isspace((unsigned char) *ptr)) ptr++; @@ -1012,9 +1016,6 @@ is_an_int(const char *str) /* * strtoint64 -- convert a string to 64-bit integer * - * This function is a slightly modified version of pg_strtoint64() from - * src/backend/utils/adt/numutils.c. - * * The function returns whether the conversion worked, and if so * "*result" is set to the result. * @@ -1023,71 +1024,25 @@ is_an_int(const char *str) bool strtoint64(const char *str, bool errorOK, int64 *result) { - const char *ptr = str; - int64 tmp = 0; - bool neg = false; - - /* - * Do our own scan, rather than relying on sscanf which might be broken - * for long long. - * - * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate - * value as a negative number. - */ - - /* skip leading spaces */ - while (*ptr && isspace((unsigned char) *ptr)) - ptr++; - - /* handle sign */ - if (*ptr == '-') - { - ptr++; - neg = true; - } - else if (*ptr == '+') - ptr++; + char *end; - /* require at least one digit */ - if (unlikely(!isdigit((unsigned char) *ptr))) - goto invalid_syntax; + errno = 0; + *result = strtoi64(str, &end, 10); - /* process digits */ - while (*ptr && isdigit((unsigned char) *ptr)) + if (unlikely(errno == ERANGE)) { - int8 digit = (*ptr++ - '0'); - - if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) || - unlikely(pg_sub_s64_overflow(tmp, digit, &tmp))) - goto out_of_range; + if (!errorOK) + pg_log_error("value \"%s\" is out of range for type bigint", str); + return false; } - /* allow trailing whitespace, but not other trailing chars */ - while (*ptr != '\0' && isspace((unsigned char) *ptr)) - ptr++; - - if (unlikely(*ptr != '\0')) - goto invalid_syntax; - - if (!neg) + if (unlikely(errno != 0 || end == str || *end != '\0')) { - if (unlikely(tmp == PG_INT64_MIN)) - goto out_of_range; - tmp = -tmp; + if (!errorOK) + pg_log_error("invalid input syntax for type bigint: \"%s\"", str); + return false; } - - *result = tmp; return true; - -out_of_range: - if (!errorOK) - pg_log_error("value \"%s\" is out of range for type bigint", str); - return false; - -invalid_syntax: - if (!errorOK) - pg_log_error("invalid input syntax for type bigint: \"%s\"", str); - return false; } /* convert string to double, detecting overflows/underflows */ @@ -1099,14 +1054,14 @@ strtodouble(const char *str, bool errorOK, double *dv) errno = 0; *dv = strtod(str, &end); - if (unlikely(errno != 0)) + if (unlikely(errno == ERANGE)) { if (!errorOK) pg_log_error("value \"%s\" is out of range for type double", str); return false; } - if (unlikely(end == str || *end != '\0')) + if (unlikely(errno != 0 || end == str || *end != '\0')) { if (!errorOK) pg_log_error("invalid input syntax for type double: \"%s\"", str);