]> granicus.if.org Git - postgresql/commitdiff
Add casts from int4 and int8 to numeric.
authorRobert Haas <rhaas@postgresql.org>
Tue, 5 Apr 2011 13:35:43 +0000 (09:35 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 5 Apr 2011 13:35:43 +0000 (09:35 -0400)
Joey Adams, per gripe from Ramanujam.  Review by myself and Tom Lane.

doc/src/sgml/datatype.sgml
src/backend/utils/adt/cash.c
src/include/catalog/catversion.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_proc.h
src/include/utils/cash.h
src/test/regress/expected/money.out
src/test/regress/sql/money.sql

index ecc79e27fc3f48ddca9f0b651404525235347158..13b888dff8f7285fff3645c09f83fe66075af3b0 100644 (file)
@@ -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>
index 67f51280c385242d5241ff6bcd57747df05687e0..4c3279759d518d16263ccd0725dceb4be9e4c389 100644 (file)
@@ -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);
+}
index e9659092198e0a2a220bab0f5fae0344598457a9..b74526b3b79a49e2c1bf02e063e120a46c73b92c 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201103201
+#define CATALOG_VERSION_NO     201104051
 
 #endif
index bf8a6fcb77db20e80fcf8fc49d6a7aecabd1def3..f7b7b768330f3eb0b7811726609d0a9e79310a5c 100644 (file)
@@ -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 ));
index cff64ba6b0239ce2932fe375432018f05769829c..7919a40487f286165fd279643d76f35eca2d94bf 100644 (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");
 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 */
 
index 81b51ad68f1cb21c523ed14c0eb85cf30399702b..3a491f9231a8cf2678c7385635f6465b027249b7 100644 (file)
@@ -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 */
index ec4169cbb060b0a259951d7afe53be947a932499..538235c4cc26820660e95fc88474f0bbbc197c45 100644 (file)
@@ -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)
+
index 580425e5043b8ffe7cd628e948264c5e1231e18e..09b9476b706172f2e2d1758e95f8c684029f06dc 100644 (file)
@@ -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;