Skip to content

Commit 9c547c9

Browse files
committed
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.
1 parent 7e327ec commit 9c547c9

File tree

1 file changed

+11
-3
lines changed

1 file changed

+11
-3
lines changed

src/bin/psql/print.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,16 +2657,24 @@ setDecimalLocale(void)
26572657

26582658
extlconv = localeconv();
26592659

2660+
/* Don't accept an empty decimal_point string */
26602661
if (*extlconv->decimal_point)
26612662
decimal_point = pg_strdup(extlconv->decimal_point);
26622663
else
26632664
decimal_point = "."; /* SQL output standard */
26642665

2665-
if (*extlconv->grouping && atoi(extlconv->grouping) > 0)
2666-
groupdigits = atoi(extlconv->grouping);
2667-
else
2666+
/*
2667+
* Although the Open Group standard allows locales to supply more than one
2668+
* group width, we consider only the first one, and we ignore any attempt
2669+
* to suppress grouping by specifying CHAR_MAX. As in the backend's
2670+
* cash.c, we must apply a range check to avoid being fooled by variant
2671+
* CHAR_MAX values.
2672+
*/
2673+
groupdigits = *extlconv->grouping;
2674+
if (groupdigits <= 0 || groupdigits > 6)
26682675
groupdigits = 3; /* most common */
26692676

2677+
/* Don't accept an empty thousands_sep string, either */
26702678
/* similar code exists in formatting.c */
26712679
if (*extlconv->thousands_sep)
26722680
thousands_sep = pg_strdup(extlconv->thousands_sep);

0 commit comments

Comments
 (0)