diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/utils/adt/cash.c | 174 |
1 files changed, 94 insertions, 80 deletions
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 32fbad2f57d..b20c358486d 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/numeric.h" #include "utils/pg_locale.h" @@ -86,6 +87,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() |