Have pg_itoa, pg_ltoa and pg_lltoa return the length of the string
authorDavid Rowley <drowley@postgresql.org>
Sat, 13 Jun 2020 00:32:00 +0000 (12:32 +1200)
committerDavid Rowley <drowley@postgresql.org>
Sat, 13 Jun 2020 00:32:00 +0000 (12:32 +1200)
Core by no means makes excessive use of these functions, but quite a large
number of those usages do require the caller to call strlen() on the
returned string.  This is quite wasteful since these functions do already
have a good idea of the length of the string, so we might as well just
have them return that.

Reviewed-by: Andrew Gierth
Discussion: https://postgr.es/m/CAApHDvrm2A5x2uHYxsqriO2cUaGcFvND%2BksC9e7Tjep0t2RK_A%40mail.gmail.com

src/backend/access/common/printsimple.c
src/backend/utils/adt/int.c
src/backend/utils/adt/int8.c
src/backend/utils/adt/numutils.c
src/include/utils/builtins.h

index 0f0b54bdae37d36a311e337a16dc88ca46211f1d..df27700df92a29e9eea975d46b52483c5f1eed9e 100644 (file)
@@ -103,9 +103,10 @@ printsimple(TupleTableSlot *slot, DestReceiver *self)
                                {
                                        int32           num = DatumGetInt32(value);
                                        char            str[12];        /* sign, 10 digits and '\0' */
+                                       int                     len;
 
-                                       pg_ltoa(num, str);
-                                       pq_sendcountedtext(&buf, str, strlen(str), false);
+                                       len = pg_ltoa(num, str);
+                                       pq_sendcountedtext(&buf, str, len, false);
                                }
                                break;
 
@@ -113,9 +114,10 @@ printsimple(TupleTableSlot *slot, DestReceiver *self)
                                {
                                        int64           num = DatumGetInt64(value);
                                        char            str[MAXINT8LEN + 1];
+                                       int                     len;
 
-                                       pg_lltoa(num, str);
-                                       pq_sendcountedtext(&buf, str, strlen(str), false);
+                                       len = pg_lltoa(num, str);
+                                       pq_sendcountedtext(&buf, str, len, false);
                                }
                                break;
 
index 63c59c56b3f9e759355e5223eb04b487bc645353..418c13e1b4cdc0beb7164a1e407f06db52f2770f 100644 (file)
@@ -191,9 +191,7 @@ int2vectorout(PG_FUNCTION_ARGS)
        {
                if (num != 0)
                        *rp++ = ' ';
-               pg_itoa(int2Array->values[num], rp);
-               while (*++rp != '\0')
-                       ;
+               rp += pg_itoa(int2Array->values[num], rp);
        }
        *rp = '\0';
        PG_RETURN_CSTRING(result);
index abba8f1df04f5df50c1a5d08c71956f969cfed82..005f68d85391f4a7299307163be7da2bd5874cfe 100644 (file)
@@ -149,9 +149,16 @@ int8out(PG_FUNCTION_ARGS)
        int64           val = PG_GETARG_INT64(0);
        char            buf[MAXINT8LEN + 1];
        char       *result;
+       int                     len;
 
-       pg_lltoa(val, buf);
-       result = pstrdup(buf);
+       len = pg_lltoa(val, buf) + 1;
+
+       /*
+        * Since the length is already known, we do a manual palloc() and memcpy()
+        * to avoid the strlen() call that would otherwise be done in pstrdup().
+        */
+       result = palloc(len);
+       memcpy(result, buf, len);
        PG_RETURN_CSTRING(result);
 }
 
index a9d3fbf758f8e1a15428baeedd24f3a59ca848e1..412ae361d2c0f665c6e835be70fa7b2f90e0a981 100644 (file)
@@ -327,16 +327,17 @@ invalid_syntax:
 
 /*
  * pg_itoa: converts a signed 16-bit integer to its string representation
+ * and returns strlen(a).
  *
  * Caller must ensure that 'a' points to enough memory to hold the result
  * (at least 7 bytes, counting a leading sign and trailing NUL).
  *
  * It doesn't seem worth implementing this separately.
  */
-void
+int
 pg_itoa(int16 i, char *a)
 {
-       pg_ltoa((int32) i, a);
+       return pg_ltoa((int32) i, a);
 }
 
 /*
@@ -404,25 +405,27 @@ pg_ultoa_n(uint32 value, char *a)
 }
 
 /*
- * NUL-terminate the output of pg_ultoa_n.
+ * pg_ltoa: converts a signed 32-bit integer to its string representation and
+ * returns strlen(a).
  *
  * It is the caller's responsibility to ensure that a is at least 12 bytes long,
  * which is enough room to hold a minus sign, a maximally long int32, and the
  * above terminating NUL.
  */
-void
+int
 pg_ltoa(int32 value, char *a)
 {
        uint32          uvalue = (uint32) value;
-       int                     len;
+       int                     len = 0;
 
        if (value < 0)
        {
                uvalue = (uint32) 0 - uvalue;
-               *a++ = '-';
+               a[len++] = '-';
        }
-       len = pg_ultoa_n(uvalue, a);
+       len += pg_ultoa_n(uvalue, a + len);
        a[len] = '\0';
+       return len;
 }
 
 /*
@@ -510,24 +513,27 @@ pg_ulltoa_n(uint64 value, char *a)
 }
 
 /*
- * pg_lltoa: convert a signed 64-bit integer to its string representation
+ * pg_lltoa: converts a signed 64-bit integer to its string representation and
+ * returns strlen(a).
  *
  * Caller must ensure that 'a' points to enough memory to hold the result
  * (at least MAXINT8LEN + 1 bytes, counting a leading sign and trailing NUL).
  */
-void
+int
 pg_lltoa(int64 value, char *a)
 {
-       int                     len;
        uint64          uvalue = value;
+       int                     len = 0;
 
        if (value < 0)
        {
-               *a++ = '-';
                uvalue = (uint64) 0 - uvalue;
+               a[len++] = '-';
        }
-       len = pg_ulltoa_n(uvalue, a);
-       a[len] = 0;
+
+       len += pg_ulltoa_n(uvalue, a + len);
+       a[len] = '\0';
+       return len;
 }
 
 
index a5c8772e95fa2e237378d0b3f0fbd6fc8c8a227a..f8595642da9b7d8f5277ef63f8db62e97f397563 100644 (file)
@@ -47,11 +47,11 @@ 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 void pg_itoa(int16 i, char *a);
+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);
-extern void pg_ltoa(int32 l, char *a);
-extern void pg_lltoa(int64 ll, char *a);
+extern int pg_ltoa(int32 l, char *a);
+extern int pg_lltoa(int64 ll, char *a);
 extern char *pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth);
 extern char *pg_ultostr(char *str, uint32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);