*** a/doc/src/sgml/datatype.sgml
--- b/doc/src/sgml/datatype.sgml
***************
*** 843,865 **** ALTER SEQUENCE tablename_'$1,000.00'.
Output is generally in the latter form but depends on the locale.
! Non-quoted numeric values can be converted to money by
! casting the numeric value to text and then
! money, for example:
! SELECT 1234::text::money;
! There is no simple way of doing the reverse in a locale-independent
! manner, namely casting a money value to a numeric type.
! If you know the currency symbol and thousands separator you can use
! regexp_replace()>:
! SELECT regexp_replace('52093.89'::money::text, '[$,]', '', 'g')::numeric;
Since the output of this data type is locale-sensitive, it might not
work to load money> data into a database that has a different
setting of lc_monetary>. To avoid problems, before
--- 843,873 ----
floating-point literals, as well as typical
currency formatting, such as '$1,000.00'.
Output is generally in the latter form but depends on the locale.
!
!
!
! Values of the numeric data type can be cast to money.
! Other numeric types can be converted to money by casting to
! numeric first, for example:
! SELECT 1234::numeric::money;
! A money value can be cast to numeric without
! loss of precision. Conversion to other types could potentially lose precision,
! and it must be done in two stages:
! SELECT '52093.89'::money::numeric::float;
+ When a money value is divided by another money value,
+ the result is double precision (i.e. a pure number, not money);
+ the currency units cancel each other out in the division.
+
+
+
Since the output of this data type is locale-sensitive, it might not
work to load money> data into a database that has a different
setting of lc_monetary>. To avoid problems, before
*** a/src/backend/utils/adt/cash.c
--- b/src/backend/utils/adt/cash.c
***************
*** 27,32 ****
--- 27,33 ----
#include "utils/builtins.h"
#include "utils/cash.h"
#include "utils/pg_locale.h"
+ #include "utils/numeric.h"
#define CASH_BUFSZ 36
***************
*** 845,847 **** cash_words(PG_FUNCTION_ARGS)
--- 846,941 ----
/* return as text datum */
PG_RETURN_TEXT_P(cstring_to_text(buf));
}
+
+ /* 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_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);
+ }
+
+ /* 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();
+
+ /*
+ * Find the number of digits after the decimal point.
+ */
+ fpoint = lconvert->frac_digits;
+ if (fpoint < 0 || fpoint > 10)
+ fpoint = 2;
+ scale = 1;
+ for (i = 0; i < fpoint; i++)
+ scale *= 10;
+
+ numeric_scale = DirectFunctionCall1(&int8_numeric, Int64GetDatum(scale));
+ amount = DirectFunctionCall2(&numeric_mul, amount, numeric_scale);
+ amount = DirectFunctionCall1(&numeric_int8, amount);
+
+ result = DatumGetInt64(amount);
+ PG_RETURN_CASH(result);
+ }
*** a/src/include/catalog/pg_cast.h
--- b/src/include/catalog/pg_cast.h
***************
*** 124,129 **** DATA(insert ( 1700 21 1783 a f ));
--- 124,131 ----
DATA(insert ( 1700 23 1744 a f ));
DATA(insert ( 1700 700 1745 i f ));
DATA(insert ( 1700 701 1746 i f ));
+ DATA(insert ( 790 1700 3823 a f ));
+ DATA(insert ( 1700 790 3824 a f ));
/* Allow explicit coercions between int4 and bool */
DATA(insert ( 23 16 2557 e f ));
*** a/src/include/catalog/pg_operator.h
--- b/src/include/catalog/pg_operator.h
***************
*** 415,420 **** DATA(insert OID = 915 ( "/" PGNSP PGUID b f f 790 21 790 0 0 cash_div_
--- 415,421 ----
DATA(insert OID = 916 ( "*" PGNSP PGUID b f f 701 790 790 908 0 flt8_mul_cash - - ));
DATA(insert OID = 917 ( "*" PGNSP PGUID b f f 23 790 790 912 0 int4_mul_cash - - ));
DATA(insert OID = 918 ( "*" PGNSP PGUID b f f 21 790 790 914 0 int2_mul_cash - - ));
+ DATA(insert OID = 3825 ( "/" PGNSP PGUID b f f 790 790 701 0 0 cash_div_cash - - ));
DATA(insert OID = 965 ( "^" PGNSP PGUID b f f 701 701 701 0 0 dpow - - ));
DATA(insert OID = 966 ( "+" PGNSP PGUID b f f 1034 1033 1034 0 0 aclinsert - - ));
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 1197,1202 **** DATA(insert OID = 919 ( flt8_mul_cash PGNSP PGUID 12 1 0 0 f f f t f i 2 0
--- 1197,1208 ----
DESCR("multiply");
DATA(insert OID = 935 ( cash_words PGNSP PGUID 12 1 0 0 f f f t f i 1 0 25 "790" _null_ _null_ _null_ _null_ cash_words _null_ _null_ _null_ ));
DESCR("output amount as words");
+ DATA(insert OID = 3822 ( cash_div_cash PGNSP PGUID 12 1 0 0 f f f t f i 2 0 701 "790 790" _null_ _null_ _null_ _null_ cash_div_cash _null_ _null_ _null_ ));
+ DESCR("divide");
+ DATA(insert OID = 3823 ( numeric PGNSP PGUID 12 1 0 0 f f f t f i 1 0 1700 "790" _null_ _null_ _null_ _null_ cash_numeric _null_ _null_ _null_ ));
+ DESCR("(internal)");
+ DATA(insert OID = 3824 ( money PGNSP PGUID 12 1 0 0 f f f t f i 1 0 790 "1700" _null_ _null_ _null_ _null_ numeric_cash _null_ _null_ _null_ ));
+ DESCR("(internal)");
/* OIDS 900 - 999 */
*** a/src/include/utils/cash.h
--- b/src/include/utils/cash.h
***************
*** 63,66 **** extern Datum cashsmaller(PG_FUNCTION_ARGS);
--- 63,70 ----
extern Datum cash_words(PG_FUNCTION_ARGS);
+ extern Datum cash_div_cash(PG_FUNCTION_ARGS);
+ extern Datum cash_numeric(PG_FUNCTION_ARGS);
+ extern Datum numeric_cash(PG_FUNCTION_ARGS);
+
#endif /* CASH_H */