Commit f5e524d9 authored by Robert Haas's avatar Robert Haas

Add casts from int4 and int8 to numeric.

Joey Adams, per gripe from Ramanujam.  Review by myself and Tom Lane.
parent 88f32b7c
......@@ -886,15 +886,22 @@ ALTER SEQUENCE <replaceable class="parameter">tablename</replaceable>_<replaceab
</para>
<para>
Values of the <type>numeric</type> data type can be cast to
<type>money</type>. Other numeric types can be converted to
<type>money</type> by casting to <type>numeric</type> first, for example:
Values of the <type>numeric</type>, <type>int</type>, and
<type>bigint</type> data types can be cast to <type>money</type>.
Conversion from the <type>real</type> and <type>double precision</type>
data types can be done by casting to <type>numeric</type> first, for
example:
<programlisting>
SELECT 1234::numeric::money;
SELECT '12.34'::float8::numeric::money;
</programlisting>
However, this is not recommended. Floating point numbers should not be
used to handle money due to the potential for rounding errors.
</para>
<para>
A <type>money</type> value can be cast to <type>numeric</type> without
loss of precision. Conversion to other types could potentially lose
precision, and it must be done in two stages, for example:
precision, and must also be done in two stages:
<programlisting>
SELECT '52093.89'::money::numeric::float8;
</programlisting>
......
......@@ -26,6 +26,7 @@
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/cash.h"
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
......@@ -92,7 +93,6 @@ num_word(Cash value)
return buf;
} /* num_word() */
/* cash_in()
* Convert a string to a cash data type.
* Format is [$]###[,]###[.##]
......@@ -938,3 +938,63 @@ numeric_cash(PG_FUNCTION_ARGS)
PG_RETURN_CASH(result);
}
/* int4_cash()
* Convert int4 (int) to cash
*/
Datum
int4_cash(PG_FUNCTION_ARGS)
{
int32 amount = PG_GETARG_INT32(0);
Cash result;
int fpoint;
int64 scale;
int i;
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;
/* compute amount * scale, checking for overflow */
result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
Int64GetDatum(scale)));
PG_RETURN_CASH(result);
}
/* int8_cash()
* Convert int8 (bigint) to cash
*/
Datum
int8_cash(PG_FUNCTION_ARGS)
{
int64 amount = PG_GETARG_INT64(0);
Cash result;
int fpoint;
int64 scale;
int i;
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;
/* compute amount * scale, checking for overflow */
result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
Int64GetDatum(scale)));
PG_RETURN_CASH(result);
}
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201103201
#define CATALOG_VERSION_NO 201104051
#endif
......@@ -126,6 +126,8 @@ 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 ));
DATA(insert ( 23 790 3811 a f ));
DATA(insert ( 20 790 3812 a f ));
/* Allow explicit coercions between int4 and bool */
DATA(insert ( 23 16 2557 e f ));
......
......@@ -971,6 +971,10 @@ DATA(insert OID = 3823 ( numeric PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1700
DESCR("convert money to numeric");
DATA(insert OID = 3824 ( money PGNSP PGUID 12 1 0 0 f f f t f s 1 0 790 "1700" _null_ _null_ _null_ _null_ numeric_cash _null_ _null_ _null_ ));
DESCR("convert numeric to money");
DATA(insert OID = 3811 ( money PGNSP PGUID 12 1 0 0 f f f t f s 1 0 790 "23" _null_ _null_ _null_ _null_ int4_cash _null_ _null_ _null_ ));
DESCR("convert int4 to money");
DATA(insert OID = 3812 ( money PGNSP PGUID 12 1 0 0 f f f t f s 1 0 790 "20" _null_ _null_ _null_ _null_ int8_cash _null_ _null_ _null_ ));
DESCR("convert int8 to money");
/* OIDS 900 - 999 */
......
......@@ -67,4 +67,7 @@ extern Datum cash_words(PG_FUNCTION_ARGS);
extern Datum cash_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_cash(PG_FUNCTION_ARGS);
extern Datum int4_cash(PG_FUNCTION_ARGS);
extern Datum int8_cash(PG_FUNCTION_ARGS);
#endif /* CASH_H */
......@@ -185,3 +185,66 @@ SELECT * FROM money_data;
$123.46
(1 row)
-- Cast int4/int8 to money
SELECT 1234567890::money;
money
-------------------
$1,234,567,890.00
(1 row)
SELECT 12345678901234567::money;
money
----------------------------
$12,345,678,901,234,567.00
(1 row)
SELECT 123456789012345678::money;
ERROR: bigint out of range
SELECT 9223372036854775807::money;
ERROR: bigint out of range
SELECT (-12345)::money;
money
-------------
-$12,345.00
(1 row)
SELECT (-1234567890)::money;
money
--------------------
-$1,234,567,890.00
(1 row)
SELECT (-12345678901234567)::money;
money
-----------------------------
-$12,345,678,901,234,567.00
(1 row)
SELECT (-123456789012345678)::money;
ERROR: bigint out of range
SELECT (-9223372036854775808)::money;
ERROR: bigint out of range
SELECT 1234567890::int4::money;
money
-------------------
$1,234,567,890.00
(1 row)
SELECT 12345678901234567::int8::money;
money
----------------------------
$12,345,678,901,234,567.00
(1 row)
SELECT (-1234567890)::int4::money;
money
--------------------
-$1,234,567,890.00
(1 row)
SELECT (-12345678901234567)::int8::money;
money
-----------------------------
-$12,345,678,901,234,567.00
(1 row)
......@@ -56,3 +56,18 @@ SELECT * FROM money_data;
DELETE FROM money_data;
INSERT INTO money_data VALUES ('$123.459');
SELECT * FROM money_data;
-- Cast int4/int8 to money
SELECT 1234567890::money;
SELECT 12345678901234567::money;
SELECT 123456789012345678::money;
SELECT 9223372036854775807::money;
SELECT (-12345)::money;
SELECT (-1234567890)::money;
SELECT (-12345678901234567)::money;
SELECT (-123456789012345678)::money;
SELECT (-9223372036854775808)::money;
SELECT 1234567890::int4::money;
SELECT 12345678901234567::int8::money;
SELECT (-1234567890)::int4::money;
SELECT (-12345678901234567)::int8::money;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment