Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit cc0d90b

Browse files
committed
to_char(float4/8): zero pad to specified length
Previously, zero padding was limited to the internal length, rather than the specified length. This allows it to match to_char(int/numeric), which always padded to the specified length. Regression tests added. BACKWARD INCOMPATIBILITY
1 parent 1933a5b commit cc0d90b

File tree

4 files changed

+163
-40
lines changed

4 files changed

+163
-40
lines changed

src/backend/utils/adt/formatting.c

+75-39
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,6 @@
113113
#define DCH_MAX_ITEM_SIZ 12 /* max localized day name */
114114
#define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */
115115

116-
/* ----------
117-
* More is in float.c
118-
* ----------
119-
*/
120-
#define MAXFLOATWIDTH 60
121-
#define MAXDOUBLEWIDTH 500
122-
123116

124117
/* ----------
125118
* Format parser structs
@@ -5214,8 +5207,7 @@ int4_to_char(PG_FUNCTION_ARGS)
52145207
/* we can do it easily because float8 won't lose any precision */
52155208
float8 val = (float8) value;
52165209

5217-
orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5218-
snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
5210+
orgnum = psprintf("%+.*e", Num.post, val);
52195211

52205212
/*
52215213
* Swap a leading positive sign for a space.
@@ -5414,7 +5406,6 @@ float4_to_char(PG_FUNCTION_ARGS)
54145406
numstr = orgnum = int_to_roman((int) rint(value));
54155407
else if (IS_EEEE(&Num))
54165408
{
5417-
numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
54185409
if (isnan(value) || is_infinite(value))
54195410
{
54205411
/*
@@ -5428,15 +5419,29 @@ float4_to_char(PG_FUNCTION_ARGS)
54285419
}
54295420
else
54305421
{
5431-
snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5422+
numstr = psprintf("%+.*e", Num.post, value);
5423+
5424+
/* prevent the display of imprecise/junk digits */
5425+
if (Num.pre + Num.post > FLT_DIG)
5426+
{
5427+
int digits = 0;
5428+
char *numstr_p;
5429+
5430+
for (numstr_p = numstr; *numstr_p && *numstr_p != 'e'; numstr_p++)
5431+
{
5432+
if (isdigit(*numstr_p))
5433+
{
5434+
if (++digits > FLT_DIG)
5435+
*numstr_p = '0';
5436+
}
5437+
}
5438+
}
54325439

54335440
/*
54345441
* Swap a leading positive sign for a space.
54355442
*/
5436-
if (*orgnum == '+')
5437-
*orgnum = ' ';
5438-
5439-
numstr = orgnum;
5443+
if (*numstr == '+')
5444+
*numstr = ' ';
54405445
}
54415446
}
54425447
else
@@ -5452,16 +5457,24 @@ float4_to_char(PG_FUNCTION_ARGS)
54525457
Num.pre += Num.multi;
54535458
}
54545459

5455-
orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
5456-
snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
5457-
numstr_pre_len = strlen(orgnum);
5460+
/* let psprintf() do the rounding */
5461+
orgnum = psprintf("%.*f", Num.post, val);
54585462

5459-
/* adjust post digits to fit max float digits */
5460-
if (numstr_pre_len >= FLT_DIG)
5461-
Num.post = 0;
5462-
else if (numstr_pre_len + Num.post > FLT_DIG)
5463-
Num.post = FLT_DIG - numstr_pre_len;
5464-
snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
5463+
/* prevent the display of imprecise/junk digits */
5464+
if (Num.pre + Num.post > FLT_DIG)
5465+
{
5466+
int digits = 0;
5467+
char *orgnum_p;
5468+
5469+
for (orgnum_p = orgnum; *orgnum_p; orgnum_p++)
5470+
{
5471+
if (isdigit(*orgnum_p))
5472+
{
5473+
if (++digits > FLT_DIG)
5474+
*orgnum_p = '0';
5475+
}
5476+
}
5477+
}
54655478

54665479
if (*orgnum == '-')
54675480
{ /* < 0 */
@@ -5520,7 +5533,6 @@ float8_to_char(PG_FUNCTION_ARGS)
55205533
numstr = orgnum = int_to_roman((int) rint(value));
55215534
else if (IS_EEEE(&Num))
55225535
{
5523-
numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
55245536
if (isnan(value) || is_infinite(value))
55255537
{
55265538
/*
@@ -5534,15 +5546,29 @@ float8_to_char(PG_FUNCTION_ARGS)
55345546
}
55355547
else
55365548
{
5537-
snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5549+
numstr = psprintf("%+.*e", Num.post, value);
5550+
5551+
/* prevent the display of imprecise/junk digits */
5552+
if (Num.pre + Num.post > DBL_DIG)
5553+
{
5554+
int digits = 0;
5555+
char *numstr_p;
5556+
5557+
for (numstr_p = numstr; *numstr_p && *numstr_p != 'e'; numstr_p++)
5558+
{
5559+
if (isdigit(*numstr_p))
5560+
{
5561+
if (++digits > DBL_DIG)
5562+
*numstr_p = '0';
5563+
}
5564+
}
5565+
}
55385566

55395567
/*
55405568
* Swap a leading positive sign for a space.
55415569
*/
5542-
if (*orgnum == '+')
5543-
*orgnum = ' ';
5544-
5545-
numstr = orgnum;
5570+
if (*numstr == '+')
5571+
*numstr = ' ';
55465572
}
55475573
}
55485574
else
@@ -5557,15 +5583,25 @@ float8_to_char(PG_FUNCTION_ARGS)
55575583
val = value * multi;
55585584
Num.pre += Num.multi;
55595585
}
5560-
orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5561-
numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
5562-
5563-
/* adjust post digits to fit max double digits */
5564-
if (numstr_pre_len >= DBL_DIG)
5565-
Num.post = 0;
5566-
else if (numstr_pre_len + Num.post > DBL_DIG)
5567-
Num.post = DBL_DIG - numstr_pre_len;
5568-
snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
5586+
5587+
/* let psprintf() do the rounding */
5588+
orgnum = psprintf("%.*f", Num.post, val);
5589+
5590+
/* prevent the display of imprecise/junk digits */
5591+
if (Num.pre + Num.post > DBL_DIG)
5592+
{
5593+
int digits = 0;
5594+
char *orgnum_p;
5595+
5596+
for (orgnum_p = orgnum; *orgnum_p; orgnum_p++)
5597+
{
5598+
if (isdigit(*orgnum_p))
5599+
{
5600+
if (++digits > DBL_DIG)
5601+
*orgnum_p = '0';
5602+
}
5603+
}
5604+
}
55695605

55705606
if (*orgnum == '-')
55715607
{ /* < 0 */

0 commit comments

Comments
 (0)