The input function of the money type has no overflow checks:
=> select '12345678901234567890'::money;
money
-----------------------------
-$13,639,628,150,831,692.72
(1 row)
The tests in the regression test file money.sql are bogus because they
only test the overflow checks of the bigint type before the cast.
Here is a patch that adds appropriate checks and tests. We could
probably remove the bogus tests.
(Is checking for < 0 a valid overflow check? We save the sign until the
very end, so it ought to work. The code in int8.c works differently there.)
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 6fcce1d6c3685cfb5bacdb89981d4f6a3911dded Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 5 Aug 2016 11:50:53 -0400
Subject: [PATCH] Add overflow checks to money type input function
---
src/backend/utils/adt/cash.c | 18 ++++++++++++++
src/test/regress/expected/money.out | 47 +++++++++++++++++++++++++++++++++++++
src/test/regress/sql/money.sql | 11 +++++++++
3 files changed, 76 insertions(+)
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index b336185..0c06f71 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -197,6 +197,12 @@ cash_in(PG_FUNCTION_ARGS)
{
value = (value * 10) + (*s - '0');
+ if (value < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type money",
+ str)));
+
if (seen_dot)
dec++;
}
@@ -216,10 +222,22 @@ cash_in(PG_FUNCTION_ARGS)
if (isdigit((unsigned char) *s) && *s >= '5')
value++;
+ if (value < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type money",
+ str)));
+
/* adjust for less than required decimal places */
for (; dec < fpoint; dec++)
value *= 10;
+ if (value < 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type money",
+ str)));
+
/*
* should only be trailing digits followed by whitespace, right paren,
* trailing sign, and/or trailing currency symbol
diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out
index 538235c..206f5c4 100644
--- a/src/test/regress/expected/money.out
+++ b/src/test/regress/expected/money.out
@@ -185,6 +185,53 @@ SELECT * FROM money_data;
$123.46
(1 row)
+-- input checks
+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: value "123456789012345678" is out of range for type money
+LINE 1: SELECT '123456789012345678'::money;
+ ^
+SELECT '9223372036854775807'::money;
+ERROR: value "9223372036854775807" is out of range for type money
+LINE 1: SELECT '9223372036854775807'::money;
+ ^
+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: value "-123456789012345678" is out of range for type money
+LINE 1: SELECT '-123456789012345678'::money;
+ ^
+SELECT '-9223372036854775808'::money;
+ERROR: value "-9223372036854775808" is out of range for type money
+LINE 1: SELECT '-9223372036854775808'::money;
+ ^
-- Cast int4/int8 to money
SELECT 1234567890::money;
money
diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql
index 09b9476..d07a616 100644
--- a/src/test/regress/sql/money.sql
+++ b/src/test/regress/sql/money.sql
@@ -57,6 +57,17 @@ CREATE TABLE money_data (m money);
INSERT INTO money_data VALUES ('$123.459');
SELECT * FROM money_data;
+-- input checks
+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;
+
-- Cast int4/int8 to money
SELECT 1234567890::money;
SELECT 12345678901234567::money;
--
2.9.2
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers