aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
authorNathan Bossart <nathan@postgresql.org>2024-07-19 11:52:32 -0500
committerNathan Bossart <nathan@postgresql.org>2024-07-19 11:52:32 -0500
commit4f962815871f6ac4eb3b516832b5c95a2f628f1b (patch)
tree6630663b66701fa28dff78fe28899948993ae8ab /src/backend/utils
parentb06fe880da1423063104ac42214b04245c3277a4 (diff)
downloadpostgresql-4f962815871f6ac4eb3b516832b5c95a2f628f1b.tar.gz
postgresql-4f962815871f6ac4eb3b516832b5c95a2f628f1b.zip
Add overflow checks to money type.
None of the arithmetic functions for the the money type handle overflow. This commit introduces several helper functions with overflow checking and makes use of them in the money type's arithmetic functions. Fixes bug #18240. Reported-by: Alexander Lakhin Author: Joseph Koshakow Discussion: https://postgr.es/m/18240-c5da758d7dc1ecf0%40postgresql.org Discussion: https://postgr.es/m/CAAvxfHdBPOyEGS7s%2Bxf4iaW0-cgiq25jpYdWBqQqvLtLe_t6tw%40mail.gmail.com Backpatch-through: 12
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/cash.c174
1 files changed, 94 insertions, 80 deletions
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index 6515fc8ec69..2a63ecfa4e9 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -26,6 +26,7 @@
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/cash.h"
+#include "utils/float.h"
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
@@ -87,6 +88,82 @@ num_word(Cash value)
return buf;
} /* num_word() */
+static inline Cash
+cash_pl_cash(Cash c1, Cash c2)
+{
+ Cash res;
+
+ if (unlikely(pg_add_s64_overflow(c1, c2, &res)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ return res;
+}
+
+static inline Cash
+cash_mi_cash(Cash c1, Cash c2)
+{
+ Cash res;
+
+ if (unlikely(pg_sub_s64_overflow(c1, c2, &res)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ return res;
+}
+
+static inline Cash
+cash_mul_float8(Cash c, float8 f)
+{
+ float8 res = rint(float8_mul((float8) c, f));
+
+ if (unlikely(isnan(res) || !FLOAT8_FITS_IN_INT64(res)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ return (Cash) res;
+}
+
+static inline Cash
+cash_div_float8(Cash c, float8 f)
+{
+ float8 res = rint(float8_div((float8) c, f));
+
+ if (unlikely(isnan(res) || !FLOAT8_FITS_IN_INT64(res)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ return (Cash) res;
+}
+
+static inline Cash
+cash_mul_int64(Cash c, int64 i)
+{
+ Cash res;
+
+ if (unlikely(pg_mul_s64_overflow(c, i, &res)))
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("money out of range")));
+
+ return res;
+}
+
+static inline Cash
+cash_div_int64(Cash c, int64 i)
+{
+ if (unlikely(i == 0))
+ ereport(ERROR,
+ (errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("division by zero")));
+
+ return c / i;
+}
+
/* cash_in()
* Convert a string to a cash data type.
* Format is [$]###[,]###[.##]
@@ -612,11 +689,8 @@ cash_pl(PG_FUNCTION_ARGS)
{
Cash c1 = PG_GETARG_CASH(0);
Cash c2 = PG_GETARG_CASH(1);
- Cash result;
-
- result = c1 + c2;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_pl_cash(c1, c2));
}
@@ -628,11 +702,8 @@ cash_mi(PG_FUNCTION_ARGS)
{
Cash c1 = PG_GETARG_CASH(0);
Cash c2 = PG_GETARG_CASH(1);
- Cash result;
-
- result = c1 - c2;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mi_cash(c1, c2));
}
@@ -664,10 +735,8 @@ cash_mul_flt8(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
float8 f = PG_GETARG_FLOAT8(1);
- Cash result;
- result = rint(c * f);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_float8(c, f));
}
@@ -679,10 +748,8 @@ flt8_mul_cash(PG_FUNCTION_ARGS)
{
float8 f = PG_GETARG_FLOAT8(0);
Cash c = PG_GETARG_CASH(1);
- Cash result;
- result = rint(f * c);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_float8(c, f));
}
@@ -694,15 +761,8 @@ cash_div_flt8(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
float8 f = PG_GETARG_FLOAT8(1);
- Cash result;
- if (f == 0.0)
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
-
- result = rint(c / f);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_div_float8(c, f));
}
@@ -714,10 +774,8 @@ cash_mul_flt4(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
float4 f = PG_GETARG_FLOAT4(1);
- Cash result;
- result = rint(c * (float8) f);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_float8(c, (float8) f));
}
@@ -729,10 +787,8 @@ flt4_mul_cash(PG_FUNCTION_ARGS)
{
float4 f = PG_GETARG_FLOAT4(0);
Cash c = PG_GETARG_CASH(1);
- Cash result;
- result = rint((float8) f * c);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_float8(c, (float8) f));
}
@@ -745,15 +801,8 @@ cash_div_flt4(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
float4 f = PG_GETARG_FLOAT4(1);
- Cash result;
-
- if (f == 0.0)
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
- result = rint(c / (float8) f);
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_div_float8(c, (float8) f));
}
@@ -765,10 +814,8 @@ cash_mul_int8(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int64 i = PG_GETARG_INT64(1);
- Cash result;
- result = c * i;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, i));
}
@@ -780,10 +827,8 @@ int8_mul_cash(PG_FUNCTION_ARGS)
{
int64 i = PG_GETARG_INT64(0);
Cash c = PG_GETARG_CASH(1);
- Cash result;
- result = i * c;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, i));
}
/* cash_div_int8()
@@ -794,16 +839,8 @@ cash_div_int8(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int64 i = PG_GETARG_INT64(1);
- Cash result;
-
- if (i == 0)
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
- result = c / i;
-
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_div_int64(c, i));
}
@@ -815,10 +852,8 @@ cash_mul_int4(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int32 i = PG_GETARG_INT32(1);
- Cash result;
- result = c * i;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, (int64) i));
}
@@ -830,10 +865,8 @@ int4_mul_cash(PG_FUNCTION_ARGS)
{
int32 i = PG_GETARG_INT32(0);
Cash c = PG_GETARG_CASH(1);
- Cash result;
- result = i * c;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, (int64) i));
}
@@ -846,16 +879,8 @@ cash_div_int4(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int32 i = PG_GETARG_INT32(1);
- Cash result;
-
- if (i == 0)
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
-
- result = c / i;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_div_int64(c, (int64) i));
}
@@ -867,10 +892,8 @@ cash_mul_int2(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int16 s = PG_GETARG_INT16(1);
- Cash result;
- result = c * s;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, (int64) s));
}
/* int2_mul_cash()
@@ -881,10 +904,8 @@ int2_mul_cash(PG_FUNCTION_ARGS)
{
int16 s = PG_GETARG_INT16(0);
Cash c = PG_GETARG_CASH(1);
- Cash result;
- result = s * c;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_mul_int64(c, (int64) s));
}
/* cash_div_int2()
@@ -896,15 +917,8 @@ cash_div_int2(PG_FUNCTION_ARGS)
{
Cash c = PG_GETARG_CASH(0);
int16 s = PG_GETARG_INT16(1);
- Cash result;
- if (s == 0)
- ereport(ERROR,
- (errcode(ERRCODE_DIVISION_BY_ZERO),
- errmsg("division by zero")));
-
- result = c / s;
- PG_RETURN_CASH(result);
+ PG_RETURN_CASH(cash_div_int64(c, (int64) s));
}
/* cashlarger()