Skip to content

Commit f5e524d

Browse files
committed
Add casts from int4 and int8 to numeric.
Joey Adams, per gripe from Ramanujam. Review by myself and Tom Lane.
1 parent 88f32b7 commit f5e524d

File tree

8 files changed

+161
-7
lines changed

8 files changed

+161
-7
lines changed

doc/src/sgml/datatype.sgml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -886,15 +886,22 @@ ALTER SEQUENCE <replaceable class="parameter">tablename</replaceable>_<replaceab
886886
</para>
887887

888888
<para>
889-
Values of the <type>numeric</type> data type can be cast to
890-
<type>money</type>. Other numeric types can be converted to
891-
<type>money</type> by casting to <type>numeric</type> first, for example:
889+
Values of the <type>numeric</type>, <type>int</type>, and
890+
<type>bigint</type> data types can be cast to <type>money</type>.
891+
Conversion from the <type>real</type> and <type>double precision</type>
892+
data types can be done by casting to <type>numeric</type> first, for
893+
example:
892894
<programlisting>
893-
SELECT 1234::numeric::money;
895+
SELECT '12.34'::float8::numeric::money;
894896
</programlisting>
897+
However, this is not recommended. Floating point numbers should not be
898+
used to handle money due to the potential for rounding errors.
899+
</para>
900+
901+
<para>
895902
A <type>money</type> value can be cast to <type>numeric</type> without
896903
loss of precision. Conversion to other types could potentially lose
897-
precision, and it must be done in two stages, for example:
904+
precision, and must also be done in two stages:
898905
<programlisting>
899906
SELECT '52093.89'::money::numeric::float8;
900907
</programlisting>

src/backend/utils/adt/cash.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "libpq/pqformat.h"
2727
#include "utils/builtins.h"
2828
#include "utils/cash.h"
29+
#include "utils/int8.h"
2930
#include "utils/numeric.h"
3031
#include "utils/pg_locale.h"
3132

@@ -92,7 +93,6 @@ num_word(Cash value)
9293
return buf;
9394
} /* num_word() */
9495

95-
9696
/* cash_in()
9797
* Convert a string to a cash data type.
9898
* Format is [$]###[,]###[.##]
@@ -938,3 +938,63 @@ numeric_cash(PG_FUNCTION_ARGS)
938938

939939
PG_RETURN_CASH(result);
940940
}
941+
942+
/* int4_cash()
943+
* Convert int4 (int) to cash
944+
*/
945+
Datum
946+
int4_cash(PG_FUNCTION_ARGS)
947+
{
948+
int32 amount = PG_GETARG_INT32(0);
949+
Cash result;
950+
int fpoint;
951+
int64 scale;
952+
int i;
953+
struct lconv *lconvert = PGLC_localeconv();
954+
955+
/* see comments about frac_digits in cash_in() */
956+
fpoint = lconvert->frac_digits;
957+
if (fpoint < 0 || fpoint > 10)
958+
fpoint = 2;
959+
960+
/* compute required scale factor */
961+
scale = 1;
962+
for (i = 0; i < fpoint; i++)
963+
scale *= 10;
964+
965+
/* compute amount * scale, checking for overflow */
966+
result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
967+
Int64GetDatum(scale)));
968+
969+
PG_RETURN_CASH(result);
970+
}
971+
972+
/* int8_cash()
973+
* Convert int8 (bigint) to cash
974+
*/
975+
Datum
976+
int8_cash(PG_FUNCTION_ARGS)
977+
{
978+
int64 amount = PG_GETARG_INT64(0);
979+
Cash result;
980+
int fpoint;
981+
int64 scale;
982+
int i;
983+
struct lconv *lconvert = PGLC_localeconv();
984+
985+
/* see comments about frac_digits in cash_in() */
986+
fpoint = lconvert->frac_digits;
987+
if (fpoint < 0 || fpoint > 10)
988+
fpoint = 2;
989+
990+
/* compute required scale factor */
991+
scale = 1;
992+
for (i = 0; i < fpoint; i++)
993+
scale *= 10;
994+
995+
/* compute amount * scale, checking for overflow */
996+
result = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(amount),
997+
Int64GetDatum(scale)));
998+
999+
PG_RETURN_CASH(result);
1000+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201103201
56+
#define CATALOG_VERSION_NO 201104051
5757

5858
#endif

src/include/catalog/pg_cast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ DATA(insert ( 1700 700 1745 i f ));
126126
DATA(insert ( 1700 701 1746 i f ));
127127
DATA(insert ( 790 1700 3823 a f ));
128128
DATA(insert ( 1700 790 3824 a f ));
129+
DATA(insert ( 23 790 3811 a f ));
130+
DATA(insert ( 20 790 3812 a f ));
129131

130132
/* Allow explicit coercions between int4 and bool */
131133
DATA(insert ( 23 16 2557 e f ));

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,10 @@ DATA(insert OID = 3823 ( numeric PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1700
971971
DESCR("convert money to numeric");
972972
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_ ));
973973
DESCR("convert numeric to money");
974+
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_ ));
975+
DESCR("convert int4 to money");
976+
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_ ));
977+
DESCR("convert int8 to money");
974978

975979
/* OIDS 900 - 999 */
976980

src/include/utils/cash.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,7 @@ extern Datum cash_words(PG_FUNCTION_ARGS);
6767
extern Datum cash_numeric(PG_FUNCTION_ARGS);
6868
extern Datum numeric_cash(PG_FUNCTION_ARGS);
6969

70+
extern Datum int4_cash(PG_FUNCTION_ARGS);
71+
extern Datum int8_cash(PG_FUNCTION_ARGS);
72+
7073
#endif /* CASH_H */

src/test/regress/expected/money.out

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,66 @@ SELECT * FROM money_data;
185185
$123.46
186186
(1 row)
187187

188+
-- Cast int4/int8 to money
189+
SELECT 1234567890::money;
190+
money
191+
-------------------
192+
$1,234,567,890.00
193+
(1 row)
194+
195+
SELECT 12345678901234567::money;
196+
money
197+
----------------------------
198+
$12,345,678,901,234,567.00
199+
(1 row)
200+
201+
SELECT 123456789012345678::money;
202+
ERROR: bigint out of range
203+
SELECT 9223372036854775807::money;
204+
ERROR: bigint out of range
205+
SELECT (-12345)::money;
206+
money
207+
-------------
208+
-$12,345.00
209+
(1 row)
210+
211+
SELECT (-1234567890)::money;
212+
money
213+
--------------------
214+
-$1,234,567,890.00
215+
(1 row)
216+
217+
SELECT (-12345678901234567)::money;
218+
money
219+
-----------------------------
220+
-$12,345,678,901,234,567.00
221+
(1 row)
222+
223+
SELECT (-123456789012345678)::money;
224+
ERROR: bigint out of range
225+
SELECT (-9223372036854775808)::money;
226+
ERROR: bigint out of range
227+
SELECT 1234567890::int4::money;
228+
money
229+
-------------------
230+
$1,234,567,890.00
231+
(1 row)
232+
233+
SELECT 12345678901234567::int8::money;
234+
money
235+
----------------------------
236+
$12,345,678,901,234,567.00
237+
(1 row)
238+
239+
SELECT (-1234567890)::int4::money;
240+
money
241+
--------------------
242+
-$1,234,567,890.00
243+
(1 row)
244+
245+
SELECT (-12345678901234567)::int8::money;
246+
money
247+
-----------------------------
248+
-$12,345,678,901,234,567.00
249+
(1 row)
250+

src/test/regress/sql/money.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,18 @@ SELECT * FROM money_data;
5656
DELETE FROM money_data;
5757
INSERT INTO money_data VALUES ('$123.459');
5858
SELECT * FROM money_data;
59+
60+
-- Cast int4/int8 to money
61+
SELECT 1234567890::money;
62+
SELECT 12345678901234567::money;
63+
SELECT 123456789012345678::money;
64+
SELECT 9223372036854775807::money;
65+
SELECT (-12345)::money;
66+
SELECT (-1234567890)::money;
67+
SELECT (-12345678901234567)::money;
68+
SELECT (-123456789012345678)::money;
69+
SELECT (-9223372036854775808)::money;
70+
SELECT 1234567890::int4::money;
71+
SELECT 12345678901234567::int8::money;
72+
SELECT (-1234567890)::int4::money;
73+
SELECT (-12345678901234567)::int8::money;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy