Skip to content

Commit f0bedf3

Browse files
committed
Fix corner case bug in numeric to_char().
Trailing-zero stripping applied by the FM specifier could strip zeroes to the left of the decimal point, for a format with no digit positions after the decimal point (such as "FM999."). Reported and diagnosed by Marti Raudsepp, though I didn't use his patch.
1 parent 7b8e10f commit f0bedf3

File tree

3 files changed

+42
-7
lines changed

3 files changed

+42
-7
lines changed

src/backend/utils/adt/formatting.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,6 +3908,9 @@ NUM_prepare_locale(NUMProc *Np)
39083908
/* ----------
39093909
* Return pointer of last relevant number after decimal point
39103910
* 12.0500 --> last relevant is '5'
3911+
* 12.0000 --> last relevant is '.'
3912+
* If there is no decimal point, return NULL (which will result in same
3913+
* behavior as if FM hadn't been specified).
39113914
* ----------
39123915
*/
39133916
static char *
@@ -3921,7 +3924,8 @@ get_last_relevant_decnum(char *num)
39213924
#endif
39223925

39233926
if (!p)
3924-
p = num;
3927+
return NULL;
3928+
39253929
result = p;
39263930

39273931
while (*(++p))
@@ -4458,13 +4462,22 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
44584462
{
44594463
Np->num_pre = plen;
44604464

4461-
if (IS_FILLMODE(Np->Num))
4465+
if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
44624466
{
4463-
if (IS_DECIMAL(Np->Num))
4464-
Np->last_relevant = get_last_relevant_decnum(
4465-
Np->number +
4466-
((Np->Num->zero_end - Np->num_pre > 0) ?
4467-
Np->Num->zero_end - Np->num_pre : 0));
4467+
Np->last_relevant = get_last_relevant_decnum(Np->number);
4468+
4469+
/*
4470+
* If any '0' specifiers are present, make sure we don't strip
4471+
* those digits.
4472+
*/
4473+
if (Np->last_relevant && Np->Num->zero_end > Np->num_pre)
4474+
{
4475+
char *last_zero;
4476+
4477+
last_zero = Np->number + (Np->Num->zero_end - Np->num_pre);
4478+
if (Np->last_relevant < last_zero)
4479+
Np->last_relevant = last_zero;
4480+
}
44684481
}
44694482

44704483
if (Np->sign_wrote == FALSE && Np->num_pre == 0)

src/test/regress/expected/numeric.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,24 @@ SELECT '' AS to_char_23, to_char(val, '9.999EEEE') FROM num_data;
11541154
| -2.493e+07
11551155
(10 rows)
11561156

1157+
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
1158+
to_char_24 | to_char
1159+
------------+---------
1160+
| 100.
1161+
(1 row)
1162+
1163+
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
1164+
to_char_25 | to_char
1165+
------------+---------
1166+
| 100
1167+
(1 row)
1168+
1169+
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
1170+
to_char_26 | to_char
1171+
------------+---------
1172+
| 100
1173+
(1 row)
1174+
11571175
-- TO_NUMBER()
11581176
--
11591177
SELECT '' AS to_number_1, to_number('-34,338,492', '99G999G999');

src/test/regress/sql/numeric.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,10 @@ SELECT '' AS to_char_21, to_char(val, '999999SG9999999999') FROM num_data;
764764
SELECT '' AS to_char_22, to_char(val, 'FM9999999999999999.999999999999999') FROM num_data;
765765
SELECT '' AS to_char_23, to_char(val, '9.999EEEE') FROM num_data;
766766

767+
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
768+
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
769+
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
770+
767771
-- TO_NUMBER()
768772
--
769773
SELECT '' AS to_number_1, to_number('-34,338,492', '99G999G999');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy