Move scanint8() to numutils.c
authorPeter Eisentraut <[email protected]>
Mon, 14 Feb 2022 20:29:45 +0000 (21:29 +0100)
committerPeter Eisentraut <[email protected]>
Mon, 14 Feb 2022 20:57:26 +0000 (21:57 +0100)
Move scanint8() to numutils.c and rename to pg_strtoint64().  We
already have a "16" and "32" version of that, and the code inside the
functions was aligned, so this move makes all three versions
consistent.  The API is also changed to no longer provide the errorOK
case.  Users that need the error checking can use strtoi64().

Reviewed-by: John Naylor <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/b239564c-cad0-b23e-c57e-166d883cb97d@enterprisedb.com

src/backend/parser/parse_node.c
src/backend/replication/pgoutput/pgoutput.c
src/backend/utils/adt/int8.c
src/backend/utils/adt/numutils.c
src/bin/pgbench/pgbench.c
src/include/utils/builtins.h
src/include/utils/int8.h [deleted file]

index 35db6b6c988e1b1f7b9dc6b8da7e809ceac58faa..a49c985d36e94b5bf4b4f0f35e2294fd15c679f1 100644 (file)
@@ -26,7 +26,6 @@
 #include "parser/parse_relation.h"
 #include "parser/parsetree.h"
 #include "utils/builtins.h"
-#include "utils/int8.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/varbit.h"
@@ -353,7 +352,6 @@ make_const(ParseState *pstate, A_Const *aconst)
 {
    Const      *con;
    Datum       val;
-   int64       val64;
    Oid         typeid;
    int         typelen;
    bool        typebyval;
@@ -384,8 +382,15 @@ make_const(ParseState *pstate, A_Const *aconst)
            break;
 
        case T_Float:
+       {
            /* could be an oversize integer as well as a float ... */
-           if (scanint8(aconst->val.fval.fval, true, &val64))
+
+           int64       val64;
+           char       *endptr;
+
+           errno = 0;
+           val64 = strtoi64(aconst->val.fval.fval, &endptr, 10);
+           if (errno == 0 && *endptr == '\0')
            {
                /*
                 * It might actually fit in int32. Probably only INT_MIN can
@@ -425,6 +430,7 @@ make_const(ParseState *pstate, A_Const *aconst)
                typebyval = false;
            }
            break;
+       }
 
        case T_Boolean:
            val = BoolGetDatum(boolVal(&aconst->val));
index 6df705f90ff0c2a2e81f2ad7b0a4d66bdf5465c2..4162bb8de7b6aa045fcee7ccd0723e64628b5bb6 100644 (file)
@@ -21,7 +21,6 @@
 #include "replication/logicalproto.h"
 #include "replication/origin.h"
 #include "replication/pgoutput.h"
-#include "utils/int8.h"
 #include "utils/inval.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -207,7 +206,8 @@ parse_output_parameters(List *options, PGOutputData *data)
        /* Check each param, whether or not we recognize it */
        if (strcmp(defel->defname, "proto_version") == 0)
        {
-           int64       parsed;
+           unsigned long parsed;
+           char       *endptr;
 
            if (protocol_version_given)
                ereport(ERROR,
@@ -215,12 +215,14 @@ parse_output_parameters(List *options, PGOutputData *data)
                         errmsg("conflicting or redundant options")));
            protocol_version_given = true;
 
-           if (!scanint8(strVal(defel->arg), true, &parsed))
+           errno = 0;
+           parsed = strtoul(strVal(defel->arg), &endptr, 10);
+           if (errno != 0 || *endptr != '\0')
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("invalid proto_version")));
 
-           if (parsed > PG_UINT32_MAX || parsed < 0)
+           if (parsed > PG_UINT32_MAX)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("proto_version \"%s\" out of range",
index ad19d154ffc820f80f6bfa21d21b2cc2eeacfd1d..4a87114a4f48e2d3798ad831b3e4dacf0435b657 100644 (file)
@@ -24,7 +24,6 @@
 #include "nodes/supportnodes.h"
 #include "optimizer/optimizer.h"
 #include "utils/builtins.h"
-#include "utils/int8.h"
 
 
 typedef struct
@@ -45,99 +44,14 @@ typedef struct
  * Formatting and conversion routines.
  *---------------------------------------------------------*/
 
-/*
- * scanint8 --- try to parse a string into an int8.
- *
- * If errorOK is false, ereport a useful error message if the string is bad.
- * If errorOK is true, just return "false" for bad input.
- */
-bool
-scanint8(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++;
-
-   /* require at least one digit */
-   if (unlikely(!isdigit((unsigned char) *ptr)))
-       goto invalid_syntax;
-
-   /* process digits */
-   while (*ptr && isdigit((unsigned char) *ptr))
-   {
-       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;
-   }
-
-   /* 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)
-   {
-       /* could fail if input is most negative number */
-       if (unlikely(tmp == PG_INT64_MIN))
-           goto out_of_range;
-       tmp = -tmp;
-   }
-
-   *result = tmp;
-   return true;
-
-out_of_range:
-   if (!errorOK)
-       ereport(ERROR,
-               (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-                errmsg("value \"%s\" is out of range for type %s",
-                       str, "bigint")));
-   return false;
-
-invalid_syntax:
-   if (!errorOK)
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                errmsg("invalid input syntax for type %s: \"%s\"",
-                       "bigint", str)));
-   return false;
-}
-
 /* int8in()
  */
 Datum
 int8in(PG_FUNCTION_ARGS)
 {
-   char       *str = PG_GETARG_CSTRING(0);
-   int64       result;
+   char       *num = PG_GETARG_CSTRING(0);
 
-   (void) scanint8(str, false, &result);
-   PG_RETURN_INT64(result);
+   PG_RETURN_INT64(pg_strtoint64(num));
 }
 
 
index 898a9e3f9a1c81a10576c2bbe5386c2066716a43..e82d23a325e28f5936b56aa06215be8886048d3a 100644 (file)
@@ -325,6 +325,90 @@ invalid_syntax:
    return 0;                   /* keep compiler quiet */
 }
 
+/*
+ * Convert input string to a signed 64 bit integer.
+ *
+ * Allows any number of leading or trailing whitespace characters. Will throw
+ * ereport() upon bad input format or overflow.
+ *
+ * NB: Accumulate input as a negative number, to deal with two's complement
+ * representation of the most negative number, which can't be represented as a
+ * positive number.
+ */
+int64
+pg_strtoint64(const char *s)
+{
+   const char *ptr = s;
+   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++;
+
+   /* require at least one digit */
+   if (unlikely(!isdigit((unsigned char) *ptr)))
+       goto invalid_syntax;
+
+   /* process digits */
+   while (*ptr && isdigit((unsigned char) *ptr))
+   {
+       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;
+   }
+
+   /* 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)
+   {
+       /* could fail if input is most negative number */
+       if (unlikely(tmp == PG_INT64_MIN))
+           goto out_of_range;
+       tmp = -tmp;
+   }
+
+   return tmp;
+
+out_of_range:
+   ereport(ERROR,
+           (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+            errmsg("value \"%s\" is out of range for type %s",
+                   s, "bigint")));
+
+invalid_syntax:
+   ereport(ERROR,
+           (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+            errmsg("invalid input syntax for type %s: \"%s\"",
+                   "bigint", s)));
+
+   return 0;                   /* keep compiler quiet */
+}
+
 /*
  * pg_itoa: converts a signed 16-bit integer to its string representation
  * and returns strlen(a).
index 97f2a1f80ae51c20235ff4beb5665aaf91c1dffc..f166a77e3a78d4c60e5aa4999ace74367b546975 100644 (file)
@@ -787,8 +787,8 @@ is_an_int(const char *str)
 /*
  * strtoint64 -- convert a string to 64-bit integer
  *
- * This function is a slightly modified version of scanint8() from
- * src/backend/utils/adt/int8.c.
+ * 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.
index d8f05a7df3abc9cd5811c48afe43a3dd7a09575d..48ddfec9ebf602e28752a772ad46388da3b20427 100644 (file)
@@ -46,6 +46,7 @@ extern int    namestrcmp(Name name, const char *str);
 extern int32 pg_atoi(const char *s, int size, int c);
 extern int16 pg_strtoint16(const char *s);
 extern int32 pg_strtoint32(const char *s);
+extern int64 pg_strtoint64(const char *s);
 extern int pg_itoa(int16 i, char *a);
 extern int pg_ultoa_n(uint32 l, char *a);
 extern int pg_ulltoa_n(uint64 l, char *a);
diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h
deleted file mode 100644 (file)
index f0386c4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * int8.h
- *   Declarations for operations on 64-bit integers.
- *
- *
- * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/utils/int8.h
- *
- * NOTES
- * These data types are supported on all 64-bit architectures, and may
- * be supported through libraries on some 32-bit machines. If your machine
- * is not currently supported, then please try to make it so, then post
- * patches to the postgresql.org hackers mailing list.
- *
- *-------------------------------------------------------------------------
- */
-#ifndef INT8_H
-#define INT8_H
-
-extern bool scanint8(const char *str, bool errorOK, int64 *result);
-
-#endif                         /* INT8_H */