summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/cash.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-07-16 02:15:56 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2010-07-16 02:15:56 +0000
commit7590ddb3eba2e8bcbd531687789f56f9e0658277 (patch)
tree83cf9eaa04325920a9d6cdf01b064ee09d467486 /src/backend/utils/adt/cash.c
parente11cfa87be2144dd9fd2c73480c708f61d40625d (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.c99
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);
+}