]> granicus.if.org Git - postgresql/commitdiff
Further fix for psql's code for locale-aware formatting of numeric output.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Sep 2015 16:20:45 +0000 (12:20 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 25 Sep 2015 16:20:45 +0000 (12:20 -0400)
(Third time's the charm, I hope.)

Additional testing disclosed that this code could mangle already-localized
output from the "money" datatype.  We can't very easily skip applying it
to "money" values, because the logic is tied to column right-justification
and people expect "money" output to be right-justified.  Short of
decoupling that, we can fix it in what should be a safe enough way by
testing to make sure the string doesn't contain any characters that would
not be expected in plain numeric output.

src/bin/psql/print.c

index 725ce8b34c44fe76c856c8d86e00af8af8101b27..74298cfe441ff52f512a6366ed3a1792e4910ff9 100644 (file)
@@ -227,18 +227,34 @@ additional_numeric_locale_len(const char *my_str)
 }
 
 /*
+ * Format a numeric value per current LC_NUMERIC locale setting
+ *
  * Returns the appropriately formatted string in a new allocated block,
- * caller must free
+ * caller must free.
+ *
+ * setDecimalLocale() must have been called earlier.
  */
 static char *
 format_numeric_locale(const char *my_str)
 {
-       int                     new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
-       char       *new_str = pg_malloc(new_len + 1);
-       int                     int_len = integer_digits(my_str);
-       int                     i,
-                               leading_digits;
-       int                     new_str_pos = 0;
+       char       *new_str;
+       int                     new_len,
+                               int_len,
+                               leading_digits,
+                               i,
+                               new_str_pos;
+
+       /*
+        * If the string doesn't look like a number, return it unchanged.  This
+        * check is essential to avoid mangling already-localized "money" values.
+        */
+       if (strspn(my_str, "0123456789+-.eE") != strlen(my_str))
+               return pg_strdup(my_str);
+
+       new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
+       new_str = pg_malloc(new_len + 1);
+       new_str_pos = 0;
+       int_len = integer_digits(my_str);
 
        /* number of digits in first thousands group */
        leading_digits = int_len % groupdigits;