Skip to content

Commit eb9a98b

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 8036097 commit eb9a98b

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
@@ -3891,6 +3891,9 @@ NUM_prepare_locale(NUMProc *Np)
38913891
/* ----------
38923892
* Return pointer of last relevant number after decimal point
38933893
* 12.0500 --> last relevant is '5'
3894+
* 12.0000 --> last relevant is '.'
3895+
* If there is no decimal point, return NULL (which will result in same
3896+
* behavior as if FM hadn't been specified).
38943897
* ----------
38953898
*/
38963899
static char *
@@ -3904,7 +3907,8 @@ get_last_relevant_decnum(char *num)
39043907
#endif
39053908

39063909
if (!p)
3907-
p = num;
3910+
return NULL;
3911+
39083912
result = p;
39093913

39103914
while (*(++p))
@@ -4432,13 +4436,22 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
44324436
{
44334437
Np->num_pre = plen;
44344438

4435-
if (IS_FILLMODE(Np->Num))
4439+
if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
44364440
{
4437-
if (IS_DECIMAL(Np->Num))
4438-
Np->last_relevant = get_last_relevant_decnum(
4439-
Np->number +
4440-
((Np->Num->zero_end - Np->num_pre > 0) ?
4441-
Np->Num->zero_end - Np->num_pre : 0));
4441+
Np->last_relevant = get_last_relevant_decnum(Np->number);
4442+
4443+
/*
4444+
* If any '0' specifiers are present, make sure we don't strip
4445+
* those digits.
4446+
*/
4447+
if (Np->last_relevant && Np->Num->zero_end > Np->num_pre)
4448+
{
4449+
char *last_zero;
4450+
4451+
last_zero = Np->number + (Np->Num->zero_end - Np->num_pre);
4452+
if (Np->last_relevant < last_zero)
4453+
Np->last_relevant = last_zero;
4454+
}
44424455
}
44434456

44444457
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
@@ -1117,6 +1117,24 @@ SELECT '' AS to_char_22, to_char(val, 'FM9999999999999999.999999999999999') FROM
11171117
| -24926804.04504742
11181118
(10 rows)
11191119

1120+
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
1121+
to_char_24 | to_char
1122+
------------+---------
1123+
| 100.
1124+
(1 row)
1125+
1126+
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
1127+
to_char_25 | to_char
1128+
------------+---------
1129+
| 100
1130+
(1 row)
1131+
1132+
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
1133+
to_char_26 | to_char
1134+
------------+---------
1135+
| 100
1136+
(1 row)
1137+
11201138
-- TO_NUMBER()
11211139
--
11221140
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
@@ -746,6 +746,10 @@ SELECT '' AS to_char_20, to_char(val, E'99999 "text" 9999 "9999" 999 "\\"text be
746746
SELECT '' AS to_char_21, to_char(val, '999999SG9999999999') FROM num_data;
747747
SELECT '' AS to_char_22, to_char(val, 'FM9999999999999999.999999999999999') FROM num_data;
748748

749+
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
750+
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
751+
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
752+
749753
-- TO_NUMBER()
750754
--
751755
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