> Or I guess we could leave this as you've written it and add support > for a cast from money to numeric.
I tried rewriting my function to use numeric, but I discovered that numeric division is not exact. (Otherwise SELECT 1::numeric / 3::numeric would result in an infinite loop.) So I went back to my float8 version and wrote a cast from money to numeric. Here is my C source code now: #include <postgres.h> #include <fmgr.h> #include <utils/cash.h> #include <utils/numeric.h> #include <utils/pg_locale.h> PG_MODULE_MAGIC; extern Datum int8_numeric(PG_FUNCTION_ARGS); extern Datum numeric_div(PG_FUNCTION_ARGS); extern Datum numeric_mul(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(cash_div_cash); /* cash_div_cash() * Divide cash by cash, returning float8. */ Datum cash_div_cash(PG_FUNCTION_ARGS) { Cash dividend = PG_GETARG_CASH(0); Cash divisor = PG_GETARG_CASH(1); float8 quotient; if (divisor == 0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero"))); quotient = (float8)dividend / (float8)divisor; PG_RETURN_FLOAT8(quotient); } PG_FUNCTION_INFO_V1(cash_numeric); /* cash_numeric() * Convert cash to numeric. */ Datum cash_numeric(PG_FUNCTION_ARGS) { Cash money = PG_GETARG_CASH(0); int fpoint; int64 scale; int i; Numeric result; Datum amount; Datum numeric_scale; Datum one; struct lconv *lconvert = PGLC_localeconv(); /* * Find the number of digits after the decimal point. * (These lines were copied from cash_in().) */ fpoint = lconvert->frac_digits; if (fpoint < 0 || fpoint > 10) fpoint = 2; scale = 1; for (i = 0; i < fpoint; i++) scale *= 10; amount = DirectFunctionCall1(&int8_numeric, Int64GetDatum(money)); one = DirectFunctionCall1(&int8_numeric, Int64GetDatum(1)); numeric_scale = DirectFunctionCall1(&int8_numeric, Int64GetDatum(scale)); numeric_scale = DirectFunctionCall2(&numeric_div, one, numeric_scale); result = DatumGetNumeric(DirectFunctionCall2(&numeric_mul, amount, numeric_scale)); result->n_sign_dscale = NUMERIC_SIGN(result) | fpoint; /* Display the right number of decimal digits. */ PG_RETURN_NUMERIC(result); } ------------------------------------------------------------------------------------ And here is the SQL it takes to load it: CREATE FUNCTION cash_div_cash(money, money) RETURNS double precision LANGUAGE c IMMUTABLE STRICT AS '$libdir/divide_money', 'cash_div_cash'; CREATE FUNCTION cash_numeric(money) RETURNS numeric LANGUAGE c IMMUTABLE STRICT AS '$libdir/divide_money', 'cash_numeric'; CREATE OPERATOR / ( PROCEDURE = cash_div_cash, LEFTARG = money, RIGHTARG = money ); CREATE CAST (money AS numeric) WITH FUNCTION cash_numeric(money) AS ASSIGNMENT; -- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs