On Wed, Apr 1, 2015 at 11:48:37AM -0400, Bruce Momjian wrote: > This should return something like 15555600000000.000... (per Oracle > output at the URL above, float4 has 6 significant digits on my compiler) > but I can't seem to figure how to get printf() to round non-fractional > parts. I am afraid the only solution is to use printf's %e format and > place the decimal point myself.
Hearing nothing, I went with the %e approach; patch attached. The new output looks right: test=> SELECT to_char(float4 '15555555555555.912345678912345678900000000000000000000000', repeat('9', 50) || '.' || repeat('9', 50)); to_char -------------------------------------------------------------------------------------------------------- 15555600000000.00000000000000000000000000000000000000000000000000 (1 row) > The fact I still don't have a complete solution suggests this is 9.6 > material but I still want to work on it so it is ready. I will keep this patch for 9.6 unless I hear otherwise. -- Bruce Momjian <br...@momjian.us> http://momjian.us EnterpriseDB http://enterprisedb.com + Everyone has their own god. +
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c new file mode 100644 index 40a353f..d283cd2 *** a/src/backend/utils/adt/formatting.c --- b/src/backend/utils/adt/formatting.c *************** *** 113,125 **** #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 --- 113,118 ---- *************** static DCHCacheEntry *DCH_cache_getnew(c *** 989,994 **** --- 982,989 ---- static NUMCacheEntry *NUM_cache_search(char *str); static NUMCacheEntry *NUM_cache_getnew(char *str); static void NUM_cache_remove(NUMCacheEntry *ent); + static char *add_pre_zero_padding(char *num_str, int decimal_shift); + static char *add_post_zero_padding(char *num_str, int pad_digits); /* ---------- *************** do { \ *** 5016,5021 **** --- 5011,5103 ---- SET_VARSIZE(result, len + VARHDRSZ); \ } while (0) + /* + * add_pre_zero_padding + * + * printf() can only round non-fractional parts of a number if the number + * is in exponential format, so this function takes a number in that format + * and adds pre-decimal zero padding. + */ + static char * + add_pre_zero_padding(char *num_str, int decimal_shift) + { + /* one for decimal point, one for trailing null byte */ + char *out = palloc(strlen(num_str) + decimal_shift + 1 + 1), *out_p = out; + char *num_str_p = num_str; + bool decimal_found = false; + + /* copy the number before 'e' and shift the decimal point */ + while (*num_str_p && *num_str_p != 'e') + { + if (*num_str_p == '.') + { + num_str_p++; + decimal_found = true; + } + else + { + *(out_p++) = *(num_str_p++); + if (decimal_found) + decimal_shift--; + } + } + + /* add zero pad digits */ + while (decimal_shift-- > 0) + *(out_p++) = '0'; + + *(out_p++) = '\0'; + + pfree(num_str); + return out; + } + + /* + * add_post_zero_padding + * + * Some sprintf() implementations have a 512-digit precision limit, and we + * need sprintf() to round to the internal precision, so this function adds + * zero padding between the mantissa and exponent of an exponential-format + * number, or after the supplied string for non-exponent strings. + */ + static char * + add_post_zero_padding(char *num_str, int pad_digits) + { + /* one for decimal point, one for trailing null byte */ + char *out = palloc(strlen(num_str) + pad_digits + 1 + 1), *out_p = out; + char *num_str_p = num_str; + bool decimal_found = false; + + /* copy the number before 'e', or the entire string if no 'e' */ + while (*num_str_p && *num_str_p != 'e') + { + if (*num_str_p == '.') + decimal_found = true; + *(out_p++) = *(num_str_p++); + } + + /* add zero pad digits */ + while (pad_digits-- > 0) + { + if (!decimal_found) + { + *(out_p++) = '.'; + decimal_found = true; + } + + *(out_p++) = '0'; + } + + /* copy 'e' and everything after */ + while (*num_str_p) + *(out_p++) = *(num_str_p++); + + *(out_p++) = '\0'; + + pfree(num_str); + return out; + } + /* ------------------- * NUMERIC to_number() (convert string to numeric) * ------------------- *************** int4_to_char(PG_FUNCTION_ARGS) *** 5214,5221 **** /* we can do it easily because float8 won't lose any precision */ float8 val = (float8) value; ! orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); ! snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val); /* * Swap a leading positive sign for a space. --- 5296,5307 ---- /* we can do it easily because float8 won't lose any precision */ float8 val = (float8) value; ! /* Use '1' if there is any Num.post, so we get a decimal point */ ! orgnum = psprintf("%+.0e", val); ! ! /* Add any additional zeros */ ! if (Num.post > 0) ! orgnum = add_post_zero_padding(orgnum, Num.post); /* * Swap a leading positive sign for a space. *************** int4_to_char(PG_FUNCTION_ARGS) *** 5253,5265 **** /* post-decimal digits? Pad out with zeros. */ if (Num.post) ! { ! numstr = (char *) palloc(numstr_pre_len + Num.post + 2); ! strcpy(numstr, orgnum); ! *(numstr + numstr_pre_len) = '.'; ! memset(numstr + numstr_pre_len + 1, '0', Num.post); ! *(numstr + numstr_pre_len + Num.post + 1) = '\0'; ! } else numstr = orgnum; --- 5339,5345 ---- /* post-decimal digits? Pad out with zeros. */ if (Num.post) ! numstr = add_post_zero_padding(pstrdup(orgnum), Num.post); else numstr = orgnum; *************** int8_to_char(PG_FUNCTION_ARGS) *** 5363,5375 **** /* post-decimal digits? Pad out with zeros. */ if (Num.post) ! { ! numstr = (char *) palloc(numstr_pre_len + Num.post + 2); ! strcpy(numstr, orgnum); ! *(numstr + numstr_pre_len) = '.'; ! memset(numstr + numstr_pre_len + 1, '0', Num.post); ! *(numstr + numstr_pre_len + Num.post + 1) = '\0'; ! } else numstr = orgnum; --- 5443,5449 ---- /* post-decimal digits? Pad out with zeros. */ if (Num.post) ! numstr = add_post_zero_padding(pstrdup(orgnum), Num.post); else numstr = orgnum; *************** float4_to_char(PG_FUNCTION_ARGS) *** 5414,5420 **** 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)) { /* --- 5488,5493 ---- *************** float4_to_char(PG_FUNCTION_ARGS) *** 5428,5448 **** } else { ! snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ ! if (*orgnum == '+') ! *orgnum = ' '; ! ! numstr = orgnum; } } else { float4 val = value; ! int numstr_pre_len; if (IS_MULTI(&Num)) { --- 5501,5526 ---- } else { ! /* We already have one decimal digit before the decimal point. */ ! numstr = psprintf("%+.*e", ! Min(Num.post, FLT_DIG + extra_float_digits - 1), value); ! ! if (Num.post > FLT_DIG + extra_float_digits - 1) ! numstr = add_post_zero_padding(numstr, ! Num.post - FLT_DIG - extra_float_digits + 1); /* * Swap a leading positive sign for a space. */ ! if (*numstr == '+') ! *numstr = ' '; } } else { float4 val = value; ! int numstr_pre_len, val_exp = 0; ! char *exp_buf; if (IS_MULTI(&Num)) { *************** float4_to_char(PG_FUNCTION_ARGS) *** 5452,5467 **** Num.pre += Num.multi; } ! orgnum = (char *) palloc(MAXFLOATWIDTH + 1); ! snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val)); ! numstr_pre_len = strlen(orgnum); ! ! /* 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 */ --- 5530,5566 ---- Num.pre += Num.multi; } ! /* Generate string with padding */ ! exp_buf = psprintf("%.*e", FLT_DIG + extra_float_digits - 1, val); ! if (strchr(exp_buf, 'e') != NULL) ! { ! val_exp = atoi(strchr(exp_buf, 'e') + 1); ! /* ! * Is the number larger than our precision? If so, we need ! * round the non-fractional part of the number. To do that, ! * we use %e so we can round the value, shift the decimal point ! * and add zeros before the decimal point. ! */ ! /* exp assumes one digit before the decimal point */ ! if (val_exp + 1 > FLT_DIG + extra_float_digits) ! { ! orgnum = add_pre_zero_padding(exp_buf, val_exp); ! if (Num.post > 0) ! orgnum = add_post_zero_padding(orgnum, Num.post); ! } ! else ! { ! /* We might have significant fractional digits */ ! pfree(exp_buf); ! orgnum = psprintf("%.*f", Min(Num.post, FLT_DIG + ! extra_float_digits - val_exp - 1), val); ! if (Num.post > FLT_DIG + extra_float_digits - val_exp - 1) ! orgnum = add_post_zero_padding(orgnum, Num.post - FLT_DIG - ! extra_float_digits + val_exp + 1); ! } ! } ! else ! orgnum = exp_buf; if (*orgnum == '-') { /* < 0 */ *************** float8_to_char(PG_FUNCTION_ARGS) *** 5520,5526 **** 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)) { /* --- 5619,5624 ---- *************** float8_to_char(PG_FUNCTION_ARGS) *** 5534,5554 **** } else { ! snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ ! if (*orgnum == '+') ! *orgnum = ' '; ! ! numstr = orgnum; } } else { float8 val = value; ! int numstr_pre_len; if (IS_MULTI(&Num)) { --- 5632,5657 ---- } else { ! /* We already have one decimal digit before the decimal point. */ ! numstr = psprintf("%+.*e", ! Min(Num.post, DBL_DIG + extra_float_digits - 1), value); ! ! if (Num.post > DBL_DIG + extra_float_digits - 1) ! numstr = add_post_zero_padding(numstr, ! Num.post - DBL_DIG - extra_float_digits + 1); /* * Swap a leading positive sign for a space. */ ! if (*numstr == '+') ! *numstr = ' '; } } else { float8 val = value; ! int numstr_pre_len, val_exp = 0; ! char *exp_buf; if (IS_MULTI(&Num)) { *************** float8_to_char(PG_FUNCTION_ARGS) *** 5557,5571 **** val = value * multi; Num.pre += Num.multi; } - orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); - numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val)); ! /* 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 */ --- 5660,5697 ---- val = value * multi; Num.pre += Num.multi; } ! /* Generate string with padding */ ! exp_buf = psprintf("%.*e", DBL_DIG + extra_float_digits - 1, val); ! if (strchr(exp_buf, 'e') != NULL) ! { ! val_exp = atoi(strchr(exp_buf, 'e') + 1); ! /* ! * Is the number larger than our precision? If so, we need ! * round the non-fractional part of the number. To do that, ! * we use %e so we can round the value, shift the decimal point ! * and add zeros before the decimal point. ! */ ! /* exp assumes one digit before the decimal point */ ! if (val_exp + 1 > DBL_DIG + extra_float_digits) ! { ! orgnum = add_pre_zero_padding(exp_buf, val_exp); ! if (Num.post > 0) ! orgnum = add_post_zero_padding(orgnum, Num.post); ! } ! else ! { ! /* We might have significant fractional digits */ ! pfree(exp_buf); ! orgnum = psprintf("%.*f", Min(Num.post, DBL_DIG + ! extra_float_digits - val_exp - 1), val); ! if (Num.post > DBL_DIG + extra_float_digits - val_exp - 1) ! orgnum = add_post_zero_padding(orgnum, Num.post - DBL_DIG - ! extra_float_digits + val_exp + 1); ! } ! } ! else ! orgnum = exp_buf; if (*orgnum == '-') { /* < 0 */ diff --git a/src/test/regress/expected/numeric.out b/src/test/regress/expected/numeric.out new file mode 100644 index 9d68145..ac30bd2 *** a/src/test/regress/expected/numeric.out --- b/src/test/regress/expected/numeric.out *************** select * from generate_series(1::numeric *** 1499,1501 **** --- 1499,1585 ---- 3 | 4 (10 rows) + -- + -- Test code path for high-precision output + -- + SELECT to_char(float8 '55555555555', '9999999999999999D99999999'); + to_char + ---------------------------- + 55555555555.00000000 + (1 row) + + SELECT to_char(float8 '55555555555', '9999999999999999D' || repeat('9', 1000)); + to_char + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + 55555555555.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.1234567891234600000000000000000000000000000000000000000 + (1 row) + + SELECT to_char(float8 '1555555555555555555555555555555555555555555555.123456789123456789', + repeat('9', 50) || '.' || repeat('9', 50)); + to_char + -------------------------------------------------------------------------------------------------------- + 1555555555555560000000000000000000000000000000.00000000000000000000000000000000000000000000000000 + (1 row) + + SELECT to_char(float8 '1555555.55555555555555555555555555555555555555', + repeat('9', 50) || '.' || repeat('9', 50)); + to_char + -------------------------------------------------------------------------------------------------------- + 1555555.55555556000000000000000000000000000000000000000000 + (1 row) + + SELECT to_char(float8 '0.00000000000000000000015555555555555555555555', + repeat('9', 50) || '.' || repeat('9', 50)); + to_char + -------------------------------------------------------------------------------------------------------- + .00000000000000000000015555555555555600000000000000 + (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 new file mode 100644 index 19f909f..79e65f6 *** a/src/test/regress/expected/window.out --- b/src/test/regress/expected/window.out *************** SELECT to_char(SUM(n::float8) OVER (ORDE *** 1806,1812 **** FROM (VALUES(1,1e20),(2,1)) n(i,n); to_char -------------------------- ! 100000000000000000000 1.0 (2 rows) --- 1806,1812 ---- FROM (VALUES(1,1e20),(2,1)) n(i,n); to_char -------------------------- ! 100000000000000000000.0 1.0 (2 rows) diff --git a/src/test/regress/sql/numeric.sql b/src/test/regress/sql/numeric.sql new file mode 100644 index 1633e4c..a47c1bb *** a/src/test/regress/sql/numeric.sql --- b/src/test/regress/sql/numeric.sql *************** select (i / (10::numeric ^ 131071))::num *** 858,860 **** --- 858,881 ---- 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 '55555555555', '9999999999999999D99999999'); + SELECT to_char(float8 '55555555555', '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 '1555555555555555555555555555555555555555555555.123456789123456789', + repeat('9', 50) || '.' || repeat('9', 50)); + SELECT to_char(float8 '1555555.55555555555555555555555555555555555555', + repeat('9', 50) || '.' || repeat('9', 50)); + SELECT to_char(float8 '0.00000000000000000000015555555555555555555555', + 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');
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers