Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sTvB5-003jlq-SD for pgsql-hackers@arkaria.postgresql.org; Wed, 17 Jul 2024 03:18:04 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1sTvB4-005ww3-8M for pgsql-hackers@arkaria.postgresql.org; Wed, 17 Jul 2024 03:18:02 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sTvB3-005wvu-Jm for pgsql-hackers@lists.postgresql.org; Wed, 17 Jul 2024 03:18:01 +0000 Received: from mail-il1-x12e.google.com ([2607:f8b0:4864:20::12e]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1sTvAz-002RLD-PZ for pgsql-hackers@lists.postgresql.org; Wed, 17 Jul 2024 03:18:00 +0000 Received: by mail-il1-x12e.google.com with SMTP id e9e14a558f8ab-3815aaa2ab9so1363295ab.0 for ; Tue, 16 Jul 2024 20:17:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1721186277; x=1721791077; darn=lists.postgresql.org; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:message-id:subject:cc:to:from:date:from:to :cc:subject:date:message-id:reply-to; bh=UmOCLQjqOZo4RGSrVhUiDc9fujgazpfSxi/RjQv/YXA=; b=fMVpGObZOISNLG9Z3qnB4THDRh5g1vbSQVpjCIR5mDcdtNJbYKkujx7+TNQKgmcDXD +rL8VQ9i3Y/JvLEN1I+3q7JnQi+D+dbGbb1RTLOwsiW4Rfw0Sc8lL41hlYIek+C3cZCP u8/uKlHiEEPyZC0DbUaBg1+4Do00DfrRnfv1kDFzJWw7RaRbkv8OrhMk9lNFWU5pOby+ EQaZfL0mv7o/vzuH9D6nIpoIkHW6QZhL+K5oUCUA+yBE5lNjiKLUQqIbriq5nRkD1edO Q1kikMRHHacnYZDZvNhbiRv8OoXBXz05HIQaVpxWyITo/cgGE0rN3ZvO1kFhz3dwGQTQ 41UQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721186277; x=1721791077; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:message-id:subject:cc:to:from:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=UmOCLQjqOZo4RGSrVhUiDc9fujgazpfSxi/RjQv/YXA=; b=fIK0Y8QGe6c6v1681nGly+hbeMaJgl/Sr3PyoepkziVdEt+3/l3Lcpo8tsUo4iaGxW Xn7Ttbu3mao/tKLxOSMUSrLR/LygdH9O8gmOk1u4FJ1C3L7HfXg+2ej+Op9fygQCrNXR LC2ymuNYINTxPDJ6wylSduRLFl4jBmmTxXleJIupDL9y0uaeC8LEJveDg94V3fxLWiJA e3nEAUA0ulgzTiiQ/s8Ksin1qKCt71SOJF0CsItnK1fLTq+PwCL6339RCyUBnrDmzVUS TSa+e0C8hVrPP30FYX+Srv8QqQi6uV6J6PIjlF0aERQ3SVIlSaN8Gp9VPVzOhrKvy3EN qJJw== X-Forwarded-Encrypted: i=1; AJvYcCWyfvHrb09ua0jZY6XD/DfotW4xXpOviwKqrHyjJD9hr+7VbCwywjn4ZQXMlO+8Cz0IrtZQRAv77EmHp2xaTv7Lut9xCFwps0yJXlshkJOAEk2+ X-Gm-Message-State: AOJu0Ywunj2zGqC7eRN3O03pVrO1cPNsizsr9AjHM+OMgzdz7LJaFSDJ qUzChhog1R0bqx3dMHJ6ihm7iQa/L8Q0zeamELLk1bFq3Y+F2j75V+hvlQ== X-Google-Smtp-Source: AGHT+IH606gVSSgDAtvpAgA/hkyj3APhxq1lD/NslC7VUqwN+AnX+USkQLHpJiok+H0IcvQFeCVxGw== X-Received: by 2002:a05:6e02:198e:b0:376:2a41:5f42 with SMTP id e9e14a558f8ab-3950ebc8939mr9453625ab.10.1721186276784; Tue, 16 Jul 2024 20:17:56 -0700 (PDT) Received: from nathan (162-195-168-172.lightspeed.stlsmo.sbcglobal.net. [162.195.168.172]) by smtp.gmail.com with ESMTPSA id e9e14a558f8ab-3950d1adb0dsm3840465ab.83.2024.07.16.20.17.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 16 Jul 2024 20:17:56 -0700 (PDT) Date: Tue, 16 Jul 2024 22:17:54 -0500 From: Nathan Bossart To: Joseph Koshakow Cc: Alexander Lakhin , Tom Lane , PostgreSQL Hackers , Andres Freund Subject: Re: Remove dependence on integer wrapping Message-ID: References: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="vjKIKYcf0kqhcu1C" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --vjKIKYcf0kqhcu1C Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On Tue, Jul 16, 2024 at 09:23:27PM -0400, Joseph Koshakow wrote: > On Tue, Jul 16, 2024 at 1:57 PM Nathan Bossart > wrote: >> The reason I suggested this is so that we could omit all the prerequisite >> isinf(), isnan(), etc. checks in the cash_mul_float8() and friends. The >> checks are slighly different, but from a quick glance it just looks like > we >> might end up relying on the FLOAT8_FITS_IN_INT64 check in more cases. > > I don't think we can omit the prerequisite isnan() checks. Neither > float8_mul() nor float8_div() reject nan inputs/result, and > FLOAT8_FITS_IN_INT64 has the following to say about inf and nan > > These macros will do the right thing for Inf, but not necessarily for > NaN, > so check isnan(num) first if that's a possibility. My instinct would be to just let float8_mul(), float8_div(), etc. handle the inputs and then to add an additional isnan() check for the result. This is how it's done elsewhere (e.g., dtoi8() in int8.c). If something about the float8 helper functions is inadequate, let's go fix those instead. > Though, I think you're right that we can remove the isinf() check from > cash_mul_float8(). That check is fully covered by FLOAT8_FITS_IN_INT64, > since all infinite inputs will result in an infinite output. That also > makes the infinite result check in float8_mul() redundant. > Additionally, I believe that the underflow check in float8_mul() is > unnecessary. val1 is an int64 casted to a float8, so it can never be > -1 < val < 1, so it can never cause an underflow to 0. So I went ahead > and removed float8_mul() since all of its checks are redundant. TBH I'd rather keep this stuff super simple by farming out the corner case handling whenever we can, even if it is redundant in a few cases. That keeps it centralized and consistent with the rest of the tree so that any fixes apply everywhere. If there's a performance angle, then maybe it's worth considering the added complexity, though... > For cash_div_float8() we have a choice. The isinf() input check > protects against the following, which is not rejected by any of > the other checks. > > test=# SELECT '5'::money / 'inf'::float8; > ?column? > ---------- > $0.00 > (1 row) > > For now, I've kept the isinf() input check to reject the above query, > let me know if you think we should allow this. We appear to allow this for other data types, so I see no reason to disallow it for the money type. I've attached an editorialized version of 0002 based on my thoughts above. -- nathan --vjKIKYcf0kqhcu1C Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="v11-0001-Handle-overflow-in-money-arithmetic.patch" From a1741b0d9be7a22b078f9d597419aaa1d4aba673 Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Thu, 13 Jun 2024 22:39:25 -0400 Subject: [PATCH v11 1/1] Handle overflow in money arithmetic --- src/backend/utils/adt/cash.c | 174 +++++++++++++++------------- src/test/regress/expected/money.out | 106 +++++++++++++++++ src/test/regress/sql/money.sql | 47 ++++++++ 3 files changed, 247 insertions(+), 80 deletions(-) diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c index 32fbad2f57..b20c358486 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() diff --git a/src/test/regress/expected/money.out b/src/test/regress/expected/money.out index 7fd4e31804..890ce1da63 100644 --- a/src/test/regress/expected/money.out +++ b/src/test/regress/expected/money.out @@ -528,3 +528,109 @@ 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 +SELECT '92233720368547758.07'::money * 2::float8; +ERROR: money out of range +SELECT '-92233720368547758.08'::money * 2::float8; +ERROR: money out of range +SELECT 2::float8 * '92233720368547758.07'::money ; +ERROR: money out of range +SELECT 2::float8 * '-92233720368547758.08'::money; +ERROR: money out of range +SELECT '92233720368547758.07'::money * 2::float4; +ERROR: money out of range +SELECT '-92233720368547758.08'::money * 2::float4; +ERROR: money out of range +SELECT 2::float4 * '92233720368547758.07'::money ; +ERROR: money out of range +SELECT 2::float4 * '-92233720368547758.08'::money; +ERROR: money out of range +SELECT '1'::money / 1.175494e-38::float8; +ERROR: money out of range +SELECT '-1'::money / 1.175494e-38::float8; +ERROR: money out of range +SELECT '1'::money / 1.175494e-38::float4; +ERROR: money out of range +SELECT '-1'::money / 1.175494e-38::float4; +ERROR: money out of range +-- Test invalid multipliers/divisors +SELECT '42'::money * 'inf'::float8; +ERROR: money out of range +SELECT '42'::money * '-inf'::float8; +ERROR: money out of range +SELECT '42'::money * 'nan'::float8; +ERROR: money out of range +SELECT 'inf'::float8 * '42'::money; +ERROR: money out of range +SELECT '-inf'::float8 * '42'::money; +ERROR: money out of range +SELECT 'nan'::float8 * '42'::money; +ERROR: money out of range +SELECT '42'::money / 'inf'::float8; + ?column? +---------- + $0.00 +(1 row) + +SELECT '42'::money / '-inf'::float8; + ?column? +---------- + $0.00 +(1 row) + +SELECT '42'::money / 'nan'::float8; +ERROR: money out of range +SELECT '42'::money * 'inf'::float4; +ERROR: money out of range +SELECT '42'::money * '-inf'::float4; +ERROR: money out of range +SELECT '42'::money * 'nan'::float4; +ERROR: money out of range +SELECT 'inf'::float4 * '42'::money; +ERROR: money out of range +SELECT '-inf'::float4 * '42'::money; +ERROR: money out of range +SELECT 'nan'::float4 * '42'::money; +ERROR: money out of range +SELECT '42'::money / 'inf'::float4; + ?column? +---------- + $0.00 +(1 row) + +SELECT '42'::money / '-inf'::float4; + ?column? +---------- + $0.00 +(1 row) + +SELECT '42'::money / 'nan'::float4; +ERROR: money out of range diff --git a/src/test/regress/sql/money.sql b/src/test/regress/sql/money.sql index 81c92dd960..4422d2816b 100644 --- a/src/test/regress/sql/money.sql +++ b/src/test/regress/sql/money.sql @@ -135,3 +135,50 @@ 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; +SELECT '92233720368547758.07'::money * 2::float8; +SELECT '-92233720368547758.08'::money * 2::float8; +SELECT 2::float8 * '92233720368547758.07'::money ; +SELECT 2::float8 * '-92233720368547758.08'::money; +SELECT '92233720368547758.07'::money * 2::float4; +SELECT '-92233720368547758.08'::money * 2::float4; +SELECT 2::float4 * '92233720368547758.07'::money ; +SELECT 2::float4 * '-92233720368547758.08'::money; +SELECT '1'::money / 1.175494e-38::float8; +SELECT '-1'::money / 1.175494e-38::float8; +SELECT '1'::money / 1.175494e-38::float4; +SELECT '-1'::money / 1.175494e-38::float4; +-- Test invalid multipliers/divisors +SELECT '42'::money * 'inf'::float8; +SELECT '42'::money * '-inf'::float8; +SELECT '42'::money * 'nan'::float8; +SELECT 'inf'::float8 * '42'::money; +SELECT '-inf'::float8 * '42'::money; +SELECT 'nan'::float8 * '42'::money; +SELECT '42'::money / 'inf'::float8; +SELECT '42'::money / '-inf'::float8; +SELECT '42'::money / 'nan'::float8; +SELECT '42'::money * 'inf'::float4; +SELECT '42'::money * '-inf'::float4; +SELECT '42'::money * 'nan'::float4; +SELECT 'inf'::float4 * '42'::money; +SELECT '-inf'::float4 * '42'::money; +SELECT 'nan'::float4 * '42'::money; +SELECT '42'::money / 'inf'::float4; +SELECT '42'::money / '-inf'::float4; +SELECT '42'::money / 'nan'::float4; -- 2.39.3 (Apple Git-146) --vjKIKYcf0kqhcu1C--