Add casts from int4 and int8 to numeric.

Joey Adams, per gripe from Ramanujam.  Review by myself and Tom Lane.
This commit is contained in:
Robert Haas 2011-04-05 09:35:43 -04:00
parent 88f32b7ca2
commit f5e524d92b
8 changed files with 161 additions and 7 deletions

View File

@ -886,15 +886,22 @@ ALTER SEQUENCE <replaceable class="parameter">tablename</replaceable>_<replaceab
</para> </para>
<para> <para>
Values of the <type>numeric</type> data type can be cast to Values of the <type>numeric</type>, <type>int</type>, and
<type>money</type>. Other numeric types can be converted to <type>bigint</type> data types can be cast to <type>money</type>.
<type>money</type> by casting to <type>numeric</type> first, for example: 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> <programlisting>
SELECT 1234::numeric::money; SELECT '12.34'::float8::numeric::money;
</programlisting> </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 A <type>money</type> value can be cast to <type>numeric</type> without
loss of precision. Conversion to other types could potentially lose 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> <programlisting>
SELECT '52093.89'::money::numeric::float8; SELECT '52093.89'::money::numeric::float8;
</programlisting> </programlisting>

View File

@ -26,6 +26,7 @@
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/cash.h" #include "utils/cash.h"
#include "utils/int8.h"
#include "utils/numeric.h" #include "utils/numeric.h"
#include "utils/pg_locale.h" #include "utils/pg_locale.h"
@ -92,7 +93,6 @@ num_word(Cash value)
return buf; return buf;
} /* num_word() */ } /* num_word() */
/* cash_in() /* cash_in()
* Convert a string to a cash data type. * Convert a string to a cash data type.
* Format is [$]###[,]###[.##] * Format is [$]###[,]###[.##]
@ -938,3 +938,63 @@ numeric_cash(PG_FUNCTION_ARGS)
PG_RETURN_CASH(result); 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);
}

View File

@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201103201 #define CATALOG_VERSION_NO 201104051
#endif #endif

View File

@ -126,6 +126,8 @@ DATA(insert ( 1700 700 1745 i f ));
DATA(insert ( 1700 701 1746 i f )); DATA(insert ( 1700 701 1746 i f ));
DATA(insert ( 790 1700 3823 a f )); DATA(insert ( 790 1700 3823 a f ));
DATA(insert ( 1700 790 3824 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 */ /* Allow explicit coercions between int4 and bool */
DATA(insert ( 23 16 2557 e f )); DATA(insert ( 23 16 2557 e f ));

View File

@ -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"); 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_ )); 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"); 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 */ /* OIDS 900 - 999 */

View File

@ -67,4 +67,7 @@ extern Datum cash_words(PG_FUNCTION_ARGS);
extern Datum cash_numeric(PG_FUNCTION_ARGS); extern Datum cash_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_cash(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 */ #endif /* CASH_H */

View File

@ -185,3 +185,66 @@ SELECT * FROM money_data;
$123.46 $123.46
(1 row) (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)

View File

@ -56,3 +56,18 @@ SELECT * FROM money_data;
DELETE FROM money_data; DELETE FROM money_data;
INSERT INTO money_data VALUES ('$123.459'); INSERT INTO money_data VALUES ('$123.459');
SELECT * FROM money_data; 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;