Commit f9ac414c authored by Bruce Momjian's avatar Bruce Momjian

Fix float4/8 to handle Infinity and Nan consistently, e.g. Infinity is a

valid result from a computation if one of the input values was infinity.
The previous code assumed an operation that returned infinity was an
overflow.

Handle underflow/overflow consistently, and add checks for aggregate
overflow.

Consistently prevent Inf/Nan from being cast to integer data types.

Fix INT_MIN % -1 to prevent overflow.

Update regression results for new error text.

Per report from Roman Kononov.
parent 0b56be83
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.75 2006/10/04 00:29:59 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.76 2007/01/02 20:00:49 momjian Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1124,6 +1124,11 @@ int4mod(PG_FUNCTION_ARGS) ...@@ -1124,6 +1124,11 @@ int4mod(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO), (errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero"))); errmsg("division by zero")));
/* SELECT ((-2147483648)::int4) % (-1); causes a floating point exception */
if (arg1 == INT_MIN && arg2 == -1)
PG_RETURN_INT32(0);
/* No overflow is possible */ /* No overflow is possible */
PG_RETURN_INT32(arg1 % arg2); PG_RETURN_INT32(arg1 % arg2);
......
...@@ -8,14 +8,14 @@ INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 '); ...@@ -8,14 +8,14 @@ INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 ');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
-- test for over and under flow -- test for over and under flow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
ERROR: type "real" value out of range: overflow ERROR: value out of range: overflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
ERROR: type "real" value out of range: overflow ERROR: value out of range: overflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
ERROR: type "real" value out of range: underflow ERROR: value out of range: underflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
ERROR: type "real" value out of range: underflow ERROR: value out of range: underflow
-- bad input -- bad input
INSERT INTO FLOAT4_TBL(f1) VALUES (''); INSERT INTO FLOAT4_TBL(f1) VALUES ('');
ERROR: invalid input syntax for type real: "" ERROR: invalid input syntax for type real: ""
...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type real: "NaN x" ...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type real: "NaN x"
SELECT ' INFINITY x'::float4; SELECT ' INFINITY x'::float4;
ERROR: invalid input syntax for type real: " INFINITY x" ERROR: invalid input syntax for type real: " INFINITY x"
SELECT 'Infinity'::float4 + 100.0; SELECT 'Infinity'::float4 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float4 / 'Infinity'::float4; SELECT 'Infinity'::float4 / 'Infinity'::float4;
?column? ?column?
---------- ----------
......
...@@ -8,14 +8,14 @@ INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 '); ...@@ -8,14 +8,14 @@ INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 ');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
-- test for over and under flow -- test for over and under flow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
ERROR: type "real" value out of range: overflow ERROR: value out of range: overflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
ERROR: type "real" value out of range: overflow ERROR: value out of range: overflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
ERROR: type "real" value out of range: underflow ERROR: value out of range: underflow
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
ERROR: type "real" value out of range: underflow ERROR: value out of range: underflow
-- bad input -- bad input
INSERT INTO FLOAT4_TBL(f1) VALUES (''); INSERT INTO FLOAT4_TBL(f1) VALUES ('');
ERROR: invalid input syntax for type real: "" ERROR: invalid input syntax for type real: ""
...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type real: "NaN x" ...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type real: "NaN x"
SELECT ' INFINITY x'::float4; SELECT ' INFINITY x'::float4;
ERROR: invalid input syntax for type real: " INFINITY x" ERROR: invalid input syntax for type real: " INFINITY x"
SELECT 'Infinity'::float4 + 100.0; SELECT 'Infinity'::float4 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float4 / 'Infinity'::float4; SELECT 'Infinity'::float4 / 'Infinity'::float4;
?column? ?column?
---------- ----------
......
...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type double precision: "NaN x" ...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type double precision: "NaN x"
SELECT ' INFINITY x'::float8; SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x" ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0; SELECT 'Infinity'::float8 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float8 / 'Infinity'::float8; SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column? ?column?
---------- ----------
...@@ -342,15 +346,15 @@ UPDATE FLOAT8_TBL ...@@ -342,15 +346,15 @@ UPDATE FLOAT8_TBL
SET f1 = FLOAT8_TBL.f1 * '-1' SET f1 = FLOAT8_TBL.f1 * '-1'
WHERE FLOAT8_TBL.f1 > '0.0'; WHERE FLOAT8_TBL.f1 > '0.0';
SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f;
ERROR: type "double precision" value out of range: overflow ERROR: value out of range: overflow
SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: overflow
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ;
ERROR: cannot take logarithm of zero ERROR: cannot take logarithm of zero
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: underflow
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL; SELECT '' AS five, * FROM FLOAT8_TBL;
......
...@@ -80,7 +80,11 @@ ERROR: invalid input syntax for type double precision: "NaN x" ...@@ -80,7 +80,11 @@ ERROR: invalid input syntax for type double precision: "NaN x"
SELECT ' INFINITY x'::float8; SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x" ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0; SELECT 'Infinity'::float8 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float8 / 'Infinity'::float8; SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column? ?column?
---------- ----------
...@@ -350,15 +354,15 @@ UPDATE FLOAT8_TBL ...@@ -350,15 +354,15 @@ UPDATE FLOAT8_TBL
SET f1 = FLOAT8_TBL.f1 * '-1' SET f1 = FLOAT8_TBL.f1 * '-1'
WHERE FLOAT8_TBL.f1 > '0.0'; WHERE FLOAT8_TBL.f1 > '0.0';
SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f;
ERROR: type "double precision" value out of range: overflow ERROR: value out of range: overflow
SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: overflow
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ;
ERROR: cannot take logarithm of zero ERROR: cannot take logarithm of zero
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: underflow
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL; SELECT '' AS five, * FROM FLOAT8_TBL;
......
...@@ -80,7 +80,11 @@ ERROR: invalid input syntax for type double precision: "NaN x" ...@@ -80,7 +80,11 @@ ERROR: invalid input syntax for type double precision: "NaN x"
SELECT ' INFINITY x'::float8; SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x" ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0; SELECT 'Infinity'::float8 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float8 / 'Infinity'::float8; SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column? ?column?
---------- ----------
...@@ -350,15 +354,15 @@ UPDATE FLOAT8_TBL ...@@ -350,15 +354,15 @@ UPDATE FLOAT8_TBL
SET f1 = FLOAT8_TBL.f1 * '-1' SET f1 = FLOAT8_TBL.f1 * '-1'
WHERE FLOAT8_TBL.f1 > '0.0'; WHERE FLOAT8_TBL.f1 > '0.0';
SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f;
ERROR: type "double precision" value out of range: overflow ERROR: value out of range: overflow
SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: overflow
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ;
ERROR: cannot take logarithm of zero ERROR: cannot take logarithm of zero
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: underflow
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL; SELECT '' AS five, * FROM FLOAT8_TBL;
......
...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type double precision: "NaN x" ...@@ -72,7 +72,11 @@ ERROR: invalid input syntax for type double precision: "NaN x"
SELECT ' INFINITY x'::float8; SELECT ' INFINITY x'::float8;
ERROR: invalid input syntax for type double precision: " INFINITY x" ERROR: invalid input syntax for type double precision: " INFINITY x"
SELECT 'Infinity'::float8 + 100.0; SELECT 'Infinity'::float8 + 100.0;
ERROR: type "double precision" value out of range: overflow ?column?
----------
Infinity
(1 row)
SELECT 'Infinity'::float8 / 'Infinity'::float8; SELECT 'Infinity'::float8 / 'Infinity'::float8;
?column? ?column?
---------- ----------
...@@ -342,15 +346,15 @@ UPDATE FLOAT8_TBL ...@@ -342,15 +346,15 @@ UPDATE FLOAT8_TBL
SET f1 = FLOAT8_TBL.f1 * '-1' SET f1 = FLOAT8_TBL.f1 * '-1'
WHERE FLOAT8_TBL.f1 > '0.0'; WHERE FLOAT8_TBL.f1 > '0.0';
SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 * '1e200' from FLOAT8_TBL f;
ERROR: type "double precision" value out of range: overflow ERROR: value out of range: overflow
SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 ^ '1e200' from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: overflow
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 = '0.0' ;
ERROR: cannot take logarithm of zero ERROR: cannot take logarithm of zero
SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ; SELECT '' AS bad, ln(f.f1) from FLOAT8_TBL f where f.f1 < '0.0' ;
ERROR: cannot take logarithm of a negative number ERROR: cannot take logarithm of a negative number
SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f; SELECT '' AS bad, exp(f.f1) from FLOAT8_TBL f;
ERROR: result is out of range ERROR: value out of range: underflow
SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
ERROR: division by zero ERROR: division by zero
SELECT '' AS five, * FROM FLOAT8_TBL; SELECT '' AS five, * FROM FLOAT8_TBL;
......
...@@ -11,10 +11,10 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20'); ...@@ -11,10 +11,10 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20'); INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
-- test for over and under flow -- test for over and under flow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40'); INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-- bad input -- bad input
INSERT INTO FLOAT4_TBL(f1) VALUES (''); INSERT INTO FLOAT4_TBL(f1) VALUES ('');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment