aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-09-25 00:00:33 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-09-25 00:00:43 -0400
commitda4af91cefaabe493577f1d6d17ee78f2e66389c (patch)
tree6a97eefaf21d656e2004a0848e95c16186740573
parentf1ee153dcf1a3bd64889f56bee6a863f54e97d99 (diff)
downloadpostgresql-da4af91cefaabe493577f1d6d17ee78f2e66389c.tar.gz
postgresql-da4af91cefaabe493577f1d6d17ee78f2e66389c.zip
Further fix for psql's code for locale-aware formatting of numeric output.
On closer inspection, those seemingly redundant atoi() calls were not so much inefficient as just plain wrong: the author of this code either had not read, or had not understood, the POSIX specification for localeconv(). The grouping field is *not* a textual digit string but separate integers encoded as chars. We'll follow the existing code as well as the backend's cash.c in only honoring the first group width, but let's at least honor it correctly. This doesn't actually result in any behavioral change in any of the locales I have installed on my Linux box, which may explain why nobody's complained; grouping width 3 is close enough to universal that it's barely worth considering other cases. Still, wrong is wrong, so back-patch.
-rw-r--r--src/bin/psql/print.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c
index ecf1137838a..725ce8b34c4 100644
--- a/src/bin/psql/print.c
+++ b/src/bin/psql/print.c
@@ -3227,16 +3227,24 @@ setDecimalLocale(void)
extlconv = localeconv();
+ /* Don't accept an empty decimal_point string */
if (*extlconv->decimal_point)
decimal_point = pg_strdup(extlconv->decimal_point);
else
decimal_point = "."; /* SQL output standard */
- if (*extlconv->grouping && atoi(extlconv->grouping) > 0)
- groupdigits = atoi(extlconv->grouping);
- else
+ /*
+ * Although the Open Group standard allows locales to supply more than one
+ * group width, we consider only the first one, and we ignore any attempt
+ * to suppress grouping by specifying CHAR_MAX. As in the backend's
+ * cash.c, we must apply a range check to avoid being fooled by variant
+ * CHAR_MAX values.
+ */
+ groupdigits = *extlconv->grouping;
+ if (groupdigits <= 0 || groupdigits > 6)
groupdigits = 3; /* most common */
+ /* Don't accept an empty thousands_sep string, either */
/* similar code exists in formatting.c */
if (*extlconv->thousands_sep)
thousands_sep = pg_strdup(extlconv->thousands_sep);