diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-16 02:15:56 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-07-16 02:15:56 +0000 |
commit | 7590ddb3eba2e8bcbd531687789f56f9e0658277 (patch) | |
tree | 83cf9eaa04325920a9d6cdf01b064ee09d467486 /src/backend/utils/adt/cash.c | |
parent | e11cfa87be2144dd9fd2c73480c708f61d40625d (diff) |
Add support for dividing money by money (yielding a float8 result) and for
casting between money and numeric.
Andy Balholm, reviewed by Kevin Grittner
Diffstat (limited to 'src/backend/utils/adt/cash.c')
-rw-r--r-- | src/backend/utils/adt/cash.c | 99 |
1 files changed, 96 insertions, 3 deletions
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 784947e4405..c33c7cdaaea 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -13,7 +13,7 @@ * this version handles 64 bit numbers and so can hold values up to * $92,233,720,368,547,758.07. * - * $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.82 2009/06/11 14:49:03 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.83 2010/07/16 02:15:53 tgl Exp $ */ #include "postgres.h" @@ -26,6 +26,7 @@ #include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/cash.h" +#include "utils/numeric.h" #include "utils/pg_locale.h" #define CASH_BUFSZ 36 @@ -114,7 +115,6 @@ cash_in(PG_FUNCTION_ARGS) psymbol; const char *nsymbol, *csymbol; - struct lconv *lconvert = PGLC_localeconv(); /* @@ -263,7 +263,6 @@ cash_out(PG_FUNCTION_ARGS) *nsymbol; char dsymbol; char convention; - struct lconv *lconvert = PGLC_localeconv(); /* see comments about frac_digits in cash_in() */ @@ -478,6 +477,26 @@ cash_mi(PG_FUNCTION_ARGS) } +/* 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); +} + + /* cash_mul_flt8() * Multiply cash by float8. */ @@ -845,3 +864,77 @@ cash_words(PG_FUNCTION_ARGS) /* return as text datum */ PG_RETURN_TEXT_P(cstring_to_text(buf)); } + + +/* cash_numeric() + * Convert cash to numeric. + */ +Datum +cash_numeric(PG_FUNCTION_ARGS) +{ + Cash money = PG_GETARG_CASH(0); + Numeric result; + int fpoint; + int64 scale; + int i; + Datum amount; + Datum numeric_scale; + Datum quotient; + struct lconv *lconvert = PGLC_localeconv(); + + /* see comments about frac_digits in cash_in() */ + fpoint = lconvert->frac_digits; + if (fpoint < 0 || fpoint > 10) + fpoint = 2; + + /* compute required scale factor */ + scale = 1; + for (i = 0; i < fpoint; i++) + scale *= 10; + + /* form the result as money / scale */ + amount = DirectFunctionCall1(int8_numeric, Int64GetDatum(money)); + numeric_scale = DirectFunctionCall1(int8_numeric, Int64GetDatum(scale)); + quotient = DirectFunctionCall2(numeric_div, amount, numeric_scale); + + /* forcibly round to exactly the intended number of digits */ + result = DatumGetNumeric(DirectFunctionCall2(numeric_round, + quotient, + Int32GetDatum(fpoint))); + + PG_RETURN_NUMERIC(result); +} + +/* numeric_cash() + * Convert numeric to cash. + */ +Datum +numeric_cash(PG_FUNCTION_ARGS) +{ + Datum amount = PG_GETARG_DATUM(0); + Cash result; + int fpoint; + int64 scale; + int i; + Datum numeric_scale; + struct lconv *lconvert = PGLC_localeconv(); + + /* see comments about frac_digits in cash_in() */ + fpoint = lconvert->frac_digits; + if (fpoint < 0 || fpoint > 10) + fpoint = 2; + + /* compute required scale factor */ + scale = 1; + for (i = 0; i < fpoint; i++) + scale *= 10; + + /* multiply the input amount by scale factor */ + numeric_scale = DirectFunctionCall1(int8_numeric, Int64GetDatum(scale)); + amount = DirectFunctionCall2(numeric_mul, amount, numeric_scale); + + /* note that numeric_int8 will round to nearest integer for us */ + result = DatumGetInt64(DirectFunctionCall1(numeric_int8, amount)); + + PG_RETURN_CASH(result); +} |