1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Add support for dividing money by money (yielding a float8 result) and for

casting between money and numeric.

Andy Balholm, reviewed by Kevin Grittner
This commit is contained in:
Tom Lane
2010-07-16 02:15:56 +00:00
parent e11cfa87be
commit 7590ddb3eb
7 changed files with 148 additions and 34 deletions

View File

@ -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);
}