From b62972223b6dcdd3199e7ef40efb8fea1c693dc8 Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Thu, 13 Jun 2024 22:39:25 -0400 Subject: [PATCH 2/2] Handle overflow in money arithmetic --- src/backend/utils/adt/cash.c | 40 ++++++++++++++++++++++++----- src/test/regress/expected/money.out | 29 +++++++++++++++++++++ src/test/regress/sql/money.sql | 16 ++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index f6f095a57b..9d7ddcb58c 100644 --- a/src/backend/utils/adt/cash.c +++ b/src/backend/utils/adt/cash.c @@ -617,6 +617,11 @@ cash_pl(PG_FUNCTION_ARGS) Cash c2 = PG_GETARG_CASH(1); Cash result; + if (pg_add_s64_overflow(c1, c2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); + result = c1 + c2; PG_RETURN_CASH(result); @@ -633,7 +638,10 @@ cash_mi(PG_FUNCTION_ARGS) Cash c2 = PG_GETARG_CASH(1); Cash result; - result = c1 - c2; + if (pg_sub_s64_overflow(c1, c2, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -770,7 +778,10 @@ cash_mul_int8(PG_FUNCTION_ARGS) int64 i = PG_GETARG_INT64(1); Cash result; - result = c * i; + if (pg_mul_s64_overflow(c, i, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -785,7 +796,10 @@ int8_mul_cash(PG_FUNCTION_ARGS) Cash c = PG_GETARG_CASH(1); Cash result; - result = i * c; + if (pg_mul_s64_overflow(i, c, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -820,7 +834,10 @@ cash_mul_int4(PG_FUNCTION_ARGS) int32 i = PG_GETARG_INT32(1); Cash result; - result = c * i; + if (pg_mul_s64_overflow(c, (int64) i, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -835,7 +852,10 @@ int4_mul_cash(PG_FUNCTION_ARGS) Cash c = PG_GETARG_CASH(1); Cash result; - result = i * c; + if (pg_mul_s64_overflow((int64) i, c, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -872,7 +892,10 @@ cash_mul_int2(PG_FUNCTION_ARGS) int16 s = PG_GETARG_INT16(1); Cash result; - result = c * s; + if (pg_mul_s64_overflow(c, (int64) s, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } @@ -886,7 +909,10 @@ int2_mul_cash(PG_FUNCTION_ARGS) Cash c = PG_GETARG_CASH(1); Cash result; - result = s * c; + if (pg_mul_s64_overflow((int64) s, c, &result)) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("money out of range"))); PG_RETURN_CASH(result); } diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out index 7fd4e31804..950e6410a4 100644 --- a/src/test/regress/expected/money.out +++ b/src/test/regress/expected/money.out @@ -528,3 +528,32 @@ SELECT '-92233720368547758.08'::money::numeric; -92233720368547758.08 (1 row) +-- Test overflow checks +SELECT '92233720368547758.07'::money + '0.01'::money; +ERROR: money out of range +SELECT '-92233720368547758.08'::money - '0.01'::money; +ERROR: money out of range +SELECT '92233720368547758.07'::money * 2::int8; +ERROR: money out of range +SELECT '-92233720368547758.08'::money * 2::int8; +ERROR: money out of range +SELECT 2::int8 * '92233720368547758.07'::money ; +ERROR: money out of range +SELECT 2::int8 * '-92233720368547758.08'::money; +ERROR: money out of range +SELECT '92233720368547758.07'::money * 2::int4; +ERROR: money out of range +SELECT '-92233720368547758.08'::money * 2::int4; +ERROR: money out of range +SELECT 2::int4 * '92233720368547758.07'::money ; +ERROR: money out of range +SELECT 2::int4 * '-92233720368547758.08'::money; +ERROR: money out of range +SELECT '92233720368547758.07'::money * 2::int2; +ERROR: money out of range +SELECT '-92233720368547758.08'::money * 2::int2; +ERROR: money out of range +SELECT 2::int2 * '92233720368547758.07'::money ; +ERROR: money out of range +SELECT 2::int2 * '-92233720368547758.08'::money; +ERROR: money out of range diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql index 81c92dd960..36b2e029fd 100644 --- a/src/test/regress/sql/money.sql +++ b/src/test/regress/sql/money.sql @@ -135,3 +135,19 @@ SELECT '12345678901234567'::money::numeric; SELECT '-12345678901234567'::money::numeric; SELECT '92233720368547758.07'::money::numeric; SELECT '-92233720368547758.08'::money::numeric; + +-- Test overflow checks +SELECT '92233720368547758.07'::money + '0.01'::money; +SELECT '-92233720368547758.08'::money - '0.01'::money; +SELECT '92233720368547758.07'::money * 2::int8; +SELECT '-92233720368547758.08'::money * 2::int8; +SELECT 2::int8 * '92233720368547758.07'::money ; +SELECT 2::int8 * '-92233720368547758.08'::money; +SELECT '92233720368547758.07'::money * 2::int4; +SELECT '-92233720368547758.08'::money * 2::int4; +SELECT 2::int4 * '92233720368547758.07'::money ; +SELECT 2::int4 * '-92233720368547758.08'::money; +SELECT '92233720368547758.07'::money * 2::int2; +SELECT '-92233720368547758.08'::money * 2::int2; +SELECT 2::int2 * '92233720368547758.07'::money ; +SELECT 2::int2 * '-92233720368547758.08'::money; \ No newline at end of file -- 2.34.1