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:
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user