*** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 782,787 **** --- 782,800 ---- + numeric_trim + + numeric_trim(numeric) + + numeric + remove trailing decimal zeroes after the decimal point + numeric_trim(8.4100) + 8.41 + + + + + pi pi() *** a/src/backend/utils/adt/numeric.c --- b/src/backend/utils/adt/numeric.c *************** *** 2825,2830 **** numeric_power(PG_FUNCTION_ARGS) --- 2825,2904 ---- PG_RETURN_NUMERIC(res); } + /* + * numeric_trim() - + * + * Remove trailing decimal zeroes after the decimal point + */ + Datum + numeric_trim(PG_FUNCTION_ARGS) + { + Numeric num = PG_GETARG_NUMERIC(0); + NumericVar arg; + Numeric res; + int dscale; + int ndigits; + + if (NUMERIC_IS_NAN(num)) + PG_RETURN_NUMERIC(make_result(&const_nan)); + + init_var_from_num(num, &arg); + + ndigits = arg.ndigits; + /* for simplicity in the loop below, do full NBASE digits at a time */ + dscale = ((arg.dscale + DEC_DIGITS - 1) / DEC_DIGITS) * DEC_DIGITS; + /* trim unstored significant trailing zeroes right away */ + if (dscale > (ndigits - arg.weight - 1) * DEC_DIGITS) + dscale = (ndigits - arg.weight - 1) * DEC_DIGITS; + while (dscale > 0 && ndigits > 0) + { + NumericDigit dig = arg.digits[ndigits - 1]; + + #if DEC_DIGITS == 4 + if ((dig % 10) != 0) + break; + if (--dscale == 0) + break; + if ((dig % 100) != 0) + break; + if (--dscale == 0) + break; + if ((dig % 1000) != 0) + break; + if (--dscale == 0) + break; + #elif DEC_DIGITS == 2 + if ((dig % 10) != 0) + break; + if (--dscale == 0) + break; + #elif DEC_DIGITS == 1 + /* nothing to do */ + #else + #error unsupported NBASE + #endif + if (dig != 0) + break; + --dscale; + --ndigits; + } + arg.dscale = dscale; + arg.ndigits = ndigits; + + /* If it's zero, normalize the sign and weight */ + if (ndigits == 0) + { + arg.sign = NUMERIC_POS; + arg.weight = 0; + arg.dscale = 0; + } + + res = make_result(&arg); + free_var(&arg); + + PG_RETURN_NUMERIC(res); + } + /* ---------------------------------------------------------------------- * *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2361,2366 **** DESCR("exponentiation"); --- 2361,2368 ---- DATA(insert OID = 2169 ( power PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_power _null_ _null_ _null_ )); DESCR("exponentiation"); DATA(insert OID = 1739 ( numeric_power PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 1700 "1700 1700" _null_ _null_ _null_ _null_ _null_ numeric_power _null_ _null_ _null_ )); + DATA(insert OID = 8888 ( numeric_trim PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 1700 "1700" _null_ _null_ _null_ _null_ _null_ numeric_trim _null_ _null_ _null_ )); + DESCR("remove trailing decimal zeroes after the decimal point"); DATA(insert OID = 1740 ( numeric PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 1700 "23" _null_ _null_ _null_ _null_ _null_ int4_numeric _null_ _null_ _null_ )); DESCR("convert int4 to numeric"); DATA(insert OID = 1741 ( log PGNSP PGUID 14 1 0 0 0 f f f f t f i s 1 0 1700 "1700" _null_ _null_ _null_ _null_ _null_ "select pg_catalog.log(10, $1)" _null_ _null_ _null_ )); *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** *** 1022,1027 **** extern Datum numeric_exp(PG_FUNCTION_ARGS); --- 1022,1028 ---- extern Datum numeric_ln(PG_FUNCTION_ARGS); extern Datum numeric_log(PG_FUNCTION_ARGS); extern Datum numeric_power(PG_FUNCTION_ARGS); + extern Datum numeric_trim(PG_FUNCTION_ARGS); extern Datum int4_numeric(PG_FUNCTION_ARGS); extern Datum numeric_int4(PG_FUNCTION_ARGS); extern Datum int8_numeric(PG_FUNCTION_ARGS); *** a/src/test/regress/expected/numeric.out --- b/src/test/regress/expected/numeric.out *************** *** 1852,1854 **** select log(3.1954752e47, 9.4792021e-73); --- 1852,2013 ---- -1.51613372350688302142917386143459361608600157692779164475351842333265418126982165 (1 row) + -- + -- Tests for numeric_trim() + -- + select numeric_trim('NaN'); + numeric_trim + -------------- + NaN + (1 row) + + select numeric_trim('0'); + numeric_trim + -------------- + 0 + (1 row) + + select numeric_trim('0.0'); + numeric_trim + -------------- + 0 + (1 row) + + select numeric_trim('0.0000000000000000000000'); + numeric_trim + -------------- + 0 + (1 row) + + select numeric_trim('1.0'); + numeric_trim + -------------- + 1 + (1 row) + + select numeric_trim('1.00'); + numeric_trim + -------------- + 1 + (1 row) + + select numeric_trim('1.00000'); + numeric_trim + -------------- + 1 + (1 row) + + select numeric_trim('1.1'); + numeric_trim + -------------- + 1.1 + (1 row) + + select numeric_trim('1.11'); + numeric_trim + -------------- + 1.11 + (1 row) + + select numeric_trim('1.111'); + numeric_trim + -------------- + 1.111 + (1 row) + + select numeric_trim('1.1111'); + numeric_trim + -------------- + 1.1111 + (1 row) + + select numeric_trim('1.11111'); + numeric_trim + -------------- + 1.11111 + (1 row) + + select numeric_trim('1.010'); + numeric_trim + -------------- + 1.01 + (1 row) + + select numeric_trim('1.0010'); + numeric_trim + -------------- + 1.001 + (1 row) + + select numeric_trim('1.00010'); + numeric_trim + -------------- + 1.0001 + (1 row) + + select numeric_trim('1.000010'); + numeric_trim + -------------- + 1.00001 + (1 row) + + select numeric_trim('1.00001000000'); + numeric_trim + -------------- + 1.00001 + (1 row) + + select numeric_trim('1.001000000'); + numeric_trim + -------------- + 1.001 + (1 row) + + select numeric_trim('5124124800.10'); + numeric_trim + -------------- + 5124124800.1 + (1 row) + + select numeric_trim('5124124800.010'); + numeric_trim + --------------- + 5124124800.01 + (1 row) + + select numeric_trim('5124124800.0010'); + numeric_trim + ---------------- + 5124124800.001 + (1 row) + + select numeric_trim('5124124800.00010'); + numeric_trim + ----------------- + 5124124800.0001 + (1 row) + + select numeric_trim('5124124800.000010'); + numeric_trim + ------------------ + 5124124800.00001 + (1 row) + + select numeric_trim('5124124800.0000010'); + numeric_trim + ------------------- + 5124124800.000001 + (1 row) + + select numeric_trim('5124124800.00000100000000000'); + numeric_trim + ------------------- + 5124124800.000001 + (1 row) + + select numeric_trim('5124124800.00100000000000'); + numeric_trim + ---------------- + 5124124800.001 + (1 row) + *** a/src/test/regress/sql/numeric.sql --- b/src/test/regress/sql/numeric.sql *************** *** 983,985 **** select log(1.23e-89, 6.4689e45); --- 983,1017 ---- select log(0.99923, 4.58934e34); select log(1.000016, 8.452010e18); select log(3.1954752e47, 9.4792021e-73); + + + -- + -- Tests for numeric_trim() + -- + + select numeric_trim('NaN'); + select numeric_trim('0'); + select numeric_trim('0.0'); + select numeric_trim('0.0000000000000000000000'); + select numeric_trim('1.0'); + select numeric_trim('1.00'); + select numeric_trim('1.00000'); + select numeric_trim('1.1'); + select numeric_trim('1.11'); + select numeric_trim('1.111'); + select numeric_trim('1.1111'); + select numeric_trim('1.11111'); + select numeric_trim('1.010'); + select numeric_trim('1.0010'); + select numeric_trim('1.00010'); + select numeric_trim('1.000010'); + select numeric_trim('1.00001000000'); + select numeric_trim('1.001000000'); + select numeric_trim('5124124800.10'); + select numeric_trim('5124124800.010'); + select numeric_trim('5124124800.0010'); + select numeric_trim('5124124800.00010'); + select numeric_trim('5124124800.000010'); + select numeric_trim('5124124800.0000010'); + select numeric_trim('5124124800.00000100000000000'); + select numeric_trim('5124124800.00100000000000');