diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 25b247ee78..40a353f513 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -113,6 +113,13 @@ #define DCH_MAX_ITEM_SIZ 12 /* max localized day name */ #define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */ +/* ---------- + * More is in float.c + * ---------- + */ +#define MAXFLOATWIDTH 60 +#define MAXDOUBLEWIDTH 500 + /* ---------- * Format parser structs @@ -5207,7 +5214,8 @@ int4_to_char(PG_FUNCTION_ARGS) /* we can do it easily because float8 won't lose any precision */ float8 val = (float8) value; - orgnum = psprintf("%+.*e", Num.post, val); + orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); + snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val); /* * Swap a leading positive sign for a space. @@ -5406,6 +5414,7 @@ float4_to_char(PG_FUNCTION_ARGS) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { + numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* @@ -5419,29 +5428,15 @@ float4_to_char(PG_FUNCTION_ARGS) } else { - numstr = psprintf("%+.*e", Num.post, value); - - /* prevent the display of imprecise/junk digits */ - if (Num.pre + Num.post > FLT_DIG) - { - int digits = 0; - char *numstr_p; - - for (numstr_p = numstr; *numstr_p && *numstr_p != 'e'; numstr_p++) - { - if (isdigit(*numstr_p)) - { - if (++digits > FLT_DIG) - *numstr_p = '0'; - } - } - } + snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ - if (*numstr == '+') - *numstr = ' '; + if (*orgnum == '+') + *orgnum = ' '; + + numstr = orgnum; } } else @@ -5457,24 +5452,16 @@ float4_to_char(PG_FUNCTION_ARGS) Num.pre += Num.multi; } - /* let psprintf() do the rounding */ - orgnum = psprintf("%.*f", Num.post, val); + orgnum = (char *) palloc(MAXFLOATWIDTH + 1); + snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val)); + numstr_pre_len = strlen(orgnum); - /* prevent the display of imprecise/junk digits */ - if (Num.pre + Num.post > FLT_DIG) - { - int digits = 0; - char *orgnum_p; - - for (orgnum_p = orgnum; *orgnum_p; orgnum_p++) - { - if (isdigit(*orgnum_p)) - { - if (++digits > FLT_DIG) - *orgnum_p = '0'; - } - } - } + /* adjust post digits to fit max float digits */ + if (numstr_pre_len >= FLT_DIG) + Num.post = 0; + else if (numstr_pre_len + Num.post > FLT_DIG) + Num.post = FLT_DIG - numstr_pre_len; + snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ @@ -5533,6 +5520,7 @@ float8_to_char(PG_FUNCTION_ARGS) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { + numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* @@ -5546,29 +5534,15 @@ float8_to_char(PG_FUNCTION_ARGS) } else { - numstr = psprintf("%+.*e", Num.post, value); - - /* prevent the display of imprecise/junk digits */ - if (Num.pre + Num.post > DBL_DIG) - { - int digits = 0; - char *numstr_p; - - for (numstr_p = numstr; *numstr_p && *numstr_p != 'e'; numstr_p++) - { - if (isdigit(*numstr_p)) - { - if (++digits > DBL_DIG) - *numstr_p = '0'; - } - } - } + snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ - if (*numstr == '+') - *numstr = ' '; + if (*orgnum == '+') + *orgnum = ' '; + + numstr = orgnum; } } else @@ -5583,25 +5557,15 @@ float8_to_char(PG_FUNCTION_ARGS) val = value * multi; Num.pre += Num.multi; } + orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); + numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val)); - /* let psprintf() do the rounding */ - orgnum = psprintf("%.*f", Num.post, val); - - /* prevent the display of imprecise/junk digits */ - if (Num.pre + Num.post > DBL_DIG) - { - int digits = 0; - char *orgnum_p; - - for (orgnum_p = orgnum; *orgnum_p; orgnum_p++) - { - if (isdigit(*orgnum_p)) - { - if (++digits > DBL_DIG) - *orgnum_p = '0'; - } - } - } + /* adjust post digits to fit max double digits */ + if (numstr_pre_len >= DBL_DIG) + Num.post = 0; + else if (numstr_pre_len + Num.post > DBL_DIG) + Num.post = DBL_DIG - numstr_pre_len; + snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out index a4d0161923..9d6814564d 100644 --- a/src/test/regress/expected/numeric.out +++ b/src/test/regress/expected/numeric.out @@ -1499,73 +1499,3 @@ select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,5,i) 3 | 4 (10 rows) --- --- Test code path for high-precision output --- -SELECT to_char(float8 '99999999999', '9999999999999999D99999999'); - to_char ----------------------------- - 99999999999.00000000 -(1 row) - -SELECT to_char(float8 '99999999999', '9999999999999999D' || repeat('9', 1000)); - to_char ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 99999999999.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -(1 row) - -SELECT to_char(float8 '1e9','999999999999999999999D9'); - to_char --------------------------- - 1000000000.0 -(1 row) - -SELECT to_char(float8 '1e20','999999999999999999999D9'); - to_char --------------------------- - 100000000000000000000.0 -(1 row) - -SELECT to_char(1e20, '999999999999999999999D9'); - to_char --------------------------- - 100000000000000000000.0 -(1 row) - -SELECT to_char(float8 '1.123456789123456789', '9.' || repeat('9', 55)); - to_char ------------------------------------------------------------- - 1.1234567891234500000000000000000000000000000000000000000 -(1 row) - -SELECT to_char(float8 '1999999999999999999999999999999999999999999999.123456789123456789', - repeat('9', 50) || '.' || repeat('9', 50)); - to_char --------------------------------------------------------------------------------------------------------- - 1999999999999990000000000000000000000000000000.00000000000000000000000000000000000000000000000000 -(1 row) - -SELECT to_char(float8 '0.1', '9D' || repeat('9', 1000)); - to_char ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - .1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -(1 row) - -SELECT to_char(int4 '1', '9D' || repeat('9', 1000) || 'EEEE'); - to_char -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e+00 -(1 row) - -SELECT to_char(float4 '1', '9D' || repeat('9', 1000) || 'EEEE'); - to_char -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e+00 -(1 row) - -SELECT to_char(float8 '1', '9D' || repeat('9', 1000) || 'EEEE'); - to_char -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e+00 -(1 row) - diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index 79e65f6e6b..19f909f3d1 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -1806,7 +1806,7 @@ SELECT to_char(SUM(n::float8) OVER (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FO FROM (VALUES(1,1e20),(2,1)) n(i,n); to_char -------------------------- - 100000000000000000000.0 + 100000000000000000000 1.0 (2 rows) diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql index 95c2203821..1633e4c375 100644 --- a/src/test/regress/sql/numeric.sql +++ b/src/test/regress/sql/numeric.sql @@ -858,20 +858,3 @@ select (i / (10::numeric ^ 131071))::numeric(1,0) select * from generate_series(1::numeric, 3::numeric) i, generate_series(i,3) j; select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,i) j; select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,5,i) j; - --- --- Test code path for high-precision output --- - -SELECT to_char(float8 '99999999999', '9999999999999999D99999999'); -SELECT to_char(float8 '99999999999', '9999999999999999D' || repeat('9', 1000)); -SELECT to_char(float8 '1e9','999999999999999999999D9'); -SELECT to_char(float8 '1e20','999999999999999999999D9'); -SELECT to_char(1e20, '999999999999999999999D9'); -SELECT to_char(float8 '1.123456789123456789', '9.' || repeat('9', 55)); -SELECT to_char(float8 '1999999999999999999999999999999999999999999999.123456789123456789', - repeat('9', 50) || '.' || repeat('9', 50)); -SELECT to_char(float8 '0.1', '9D' || repeat('9', 1000)); -SELECT to_char(int4 '1', '9D' || repeat('9', 1000) || 'EEEE'); -SELECT to_char(float4 '1', '9D' || repeat('9', 1000) || 'EEEE'); -SELECT to_char(float8 '1', '9D' || repeat('9', 1000) || 'EEEE');