Fix for bug #31236: Inconsistent division by zero behavior for
floating point numbers Some math functions did not check if the result is a valid number (i.e. neither of +-inf or nan). Fixed by validating the result where necessary and returning NULL in case of invalid result.
This commit is contained in:
parent
947529acf3
commit
8d222210c7
@ -991,8 +991,8 @@ case $SYSTEM_TYPE in
|
||||
;;
|
||||
*hpux11.*)
|
||||
AC_MSG_WARN([Enabling workarounds for hpux 11])
|
||||
CFLAGS="$CFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE -DHAVE_BROKEN_GETPASS -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT"
|
||||
CXXFLAGS="$CXXFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -DDONT_USE_FINITE -D_INCLUDE_LONGLONG -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT"
|
||||
CFLAGS="$CFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -DHAVE_BROKEN_GETPASS -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT"
|
||||
CXXFLAGS="$CXXFLAGS -DHPUX11 -DSNPRINTF_RETURN_TRUNC -DHAVE_BROKEN_PREAD -D_INCLUDE_LONGLONG -DNO_FCNTL_NONBLOCK -DDO_NOT_REMOVE_THREAD_WRAPPERS -DHAVE_BROKEN_PTHREAD_COND_TIMEDWAIT"
|
||||
if test "$with_named_thread" = "no"
|
||||
then
|
||||
AC_MSG_WARN([Using --with-named-thread=-lpthread])
|
||||
|
@ -486,9 +486,6 @@ C_MODE_END
|
||||
#include <sys/stream.h> /* HPUX 10.20 defines ulong here. UGLY !!! */
|
||||
#define HAVE_ULONG
|
||||
#endif
|
||||
#ifdef DONT_USE_FINITE /* HPUX 11.x has is_finite() */
|
||||
#undef HAVE_FINITE
|
||||
#endif
|
||||
#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) && defined(THREAD)
|
||||
/* Fix bug in setrlimit */
|
||||
#undef setrlimit
|
||||
@ -858,9 +855,13 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
||||
#define SIZE_T_MAX ~((size_t) 0)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FINITE
|
||||
#ifndef isfinite
|
||||
#ifdef HAVE_FINITE
|
||||
#define isfinite(x) finite(x)
|
||||
#else
|
||||
#define finite(x) (1.0 / fabs(x) > 0.0)
|
||||
#endif
|
||||
#endif /* HAVE_FINITE */
|
||||
#endif /* isfinite */
|
||||
|
||||
#ifndef HAVE_ISNAN
|
||||
#define isnan(x) ((x) != (x))
|
||||
@ -870,7 +871,7 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
||||
/* isinf() can be used in both C and C++ code */
|
||||
#define my_isinf(X) isinf(X)
|
||||
#else
|
||||
#define my_isinf(X) (!finite(X) && !isnan(X))
|
||||
#define my_isinf(X) (!isfinite(X) && !isnan(X))
|
||||
#endif
|
||||
|
||||
/* Define missing math constants. */
|
||||
|
@ -408,3 +408,22 @@ a DIV 2
|
||||
0
|
||||
DROP TABLE t1;
|
||||
End of 5.0 tests
|
||||
SELECT 1e308 + 1e308;
|
||||
1e308 + 1e308
|
||||
NULL
|
||||
SELECT -1e308 - 1e308;
|
||||
-1e308 - 1e308
|
||||
NULL
|
||||
SELECT 1e300 * 1e300;
|
||||
1e300 * 1e300
|
||||
NULL
|
||||
SELECT 1e300 / 1e-300;
|
||||
1e300 / 1e-300
|
||||
NULL
|
||||
SELECT EXP(750);
|
||||
EXP(750)
|
||||
NULL
|
||||
SELECT POW(10, 309);
|
||||
POW(10, 309)
|
||||
NULL
|
||||
End of 5.1 tests
|
||||
|
@ -895,7 +895,6 @@ ERROR 22003: Out of range value for column 'col1' at row 1
|
||||
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
|
||||
ERROR 22003: Out of range value for column 'col2' at row 1
|
||||
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
|
||||
ERROR 22003: Out of range value for column 'col1' at row 3
|
||||
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
|
||||
ERROR 22012: Division by 0
|
||||
UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
|
||||
@ -923,10 +922,10 @@ SELECT * FROM t1;
|
||||
col1 col2
|
||||
-2.2e-307 0
|
||||
1e-303 0
|
||||
1.7e+308 1.7e+308
|
||||
NULL 1.7e+308
|
||||
-2.2e-307 0
|
||||
-2e-307 0
|
||||
1.7e+308 1.7e+308
|
||||
NULL 1.7e+308
|
||||
0 NULL
|
||||
2 NULL
|
||||
NULL NULL
|
||||
|
@ -248,5 +248,17 @@ INSERT INTO t1 VALUES ('a');
|
||||
SELECT a DIV 2 FROM t1 UNION SELECT a DIV 2 FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 5.0 tests
|
||||
|
||||
#
|
||||
# Bug #31236: Inconsistent division by zero behavior for floating point numbers
|
||||
#
|
||||
|
||||
SELECT 1e308 + 1e308;
|
||||
SELECT -1e308 - 1e308;
|
||||
SELECT 1e300 * 1e300;
|
||||
SELECT 1e300 / 1e-300;
|
||||
SELECT EXP(750);
|
||||
SELECT POW(10, 309);
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
@ -822,7 +822,6 @@ INSERT INTO t1 (col2) VALUES (-1.1E-3);
|
||||
INSERT INTO t1 (col1) VALUES ('+1.8E+309');
|
||||
--error 1264
|
||||
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
|
||||
--error 1264
|
||||
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
|
||||
--error 1365
|
||||
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
|
||||
|
@ -2263,13 +2263,11 @@ int Field_decimal::store(double nr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FINITE
|
||||
if (!finite(nr)) // Handle infinity as special case
|
||||
if (!isfinite(nr)) // Handle infinity as special case
|
||||
{
|
||||
overflow(nr < 0.0);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
reg4 uint i;
|
||||
size_t length;
|
||||
|
@ -1104,7 +1104,7 @@ double Item_func_plus::real_op()
|
||||
double value= args[0]->val_real() + args[1]->val_real();
|
||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||
return 0.0;
|
||||
return value;
|
||||
return fix_result(value);
|
||||
}
|
||||
|
||||
|
||||
@ -1186,7 +1186,7 @@ double Item_func_minus::real_op()
|
||||
double value= args[0]->val_real() - args[1]->val_real();
|
||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||
return 0.0;
|
||||
return value;
|
||||
return fix_result(value);
|
||||
}
|
||||
|
||||
|
||||
@ -1224,7 +1224,7 @@ double Item_func_mul::real_op()
|
||||
double value= args[0]->val_real() * args[1]->val_real();
|
||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||
return 0.0;
|
||||
return value;
|
||||
return fix_result(value);
|
||||
}
|
||||
|
||||
|
||||
@ -1282,7 +1282,7 @@ double Item_func_div::real_op()
|
||||
signal_divide_by_null();
|
||||
return 0.0;
|
||||
}
|
||||
return value/val2;
|
||||
return fix_result(value/val2);
|
||||
}
|
||||
|
||||
|
||||
@ -1655,7 +1655,7 @@ double Item_func_exp::val_real()
|
||||
double value= args[0]->val_real();
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0.0; /* purecov: inspected */
|
||||
return exp(value);
|
||||
return fix_result(exp(value));
|
||||
}
|
||||
|
||||
double Item_func_sqrt::val_real()
|
||||
@ -1674,7 +1674,7 @@ double Item_func_pow::val_real()
|
||||
double val2= args[1]->val_real();
|
||||
if ((null_value=(args[0]->null_value || args[1]->null_value)))
|
||||
return 0.0; /* purecov: inspected */
|
||||
return pow(value,val2);
|
||||
return fix_result(pow(value,val2));
|
||||
}
|
||||
|
||||
// Trigonometric functions
|
||||
@ -1686,7 +1686,7 @@ double Item_func_acos::val_real()
|
||||
volatile double value= args[0]->val_real();
|
||||
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
||||
return 0.0;
|
||||
return fix_result(acos(value));
|
||||
return acos(value);
|
||||
}
|
||||
|
||||
double Item_func_asin::val_real()
|
||||
@ -1696,7 +1696,7 @@ double Item_func_asin::val_real()
|
||||
volatile double value= args[0]->val_real();
|
||||
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
||||
return 0.0;
|
||||
return fix_result(asin(value));
|
||||
return asin(value);
|
||||
}
|
||||
|
||||
double Item_func_atan::val_real()
|
||||
@ -1712,7 +1712,7 @@ double Item_func_atan::val_real()
|
||||
return 0.0;
|
||||
return fix_result(atan2(value,val2));
|
||||
}
|
||||
return fix_result(atan(value));
|
||||
return atan(value);
|
||||
}
|
||||
|
||||
double Item_func_cos::val_real()
|
||||
@ -1721,7 +1721,7 @@ double Item_func_cos::val_real()
|
||||
double value= args[0]->val_real();
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0.0;
|
||||
return fix_result(cos(value));
|
||||
return cos(value);
|
||||
}
|
||||
|
||||
double Item_func_sin::val_real()
|
||||
@ -1730,7 +1730,7 @@ double Item_func_sin::val_real()
|
||||
double value= args[0]->val_real();
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0.0;
|
||||
return fix_result(sin(value));
|
||||
return sin(value);
|
||||
}
|
||||
|
||||
double Item_func_tan::val_real()
|
||||
|
@ -192,6 +192,13 @@ public:
|
||||
void * arg, traverse_order order);
|
||||
bool is_expensive_processor(uchar *arg);
|
||||
virtual bool is_expensive() { return 0; }
|
||||
inline double fix_result(double value)
|
||||
{
|
||||
if (isfinite(value))
|
||||
return value;
|
||||
null_value=1;
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -499,18 +506,6 @@ class Item_dec_func :public Item_real_func
|
||||
decimals=NOT_FIXED_DEC; max_length=float_length(decimals);
|
||||
maybe_null=1;
|
||||
}
|
||||
inline double fix_result(double value)
|
||||
{
|
||||
#ifndef HAVE_FINITE
|
||||
return value;
|
||||
#else
|
||||
/* The following should be safe, even if we compare doubles */
|
||||
if (finite(value) && value != POSTFIX_ERROR)
|
||||
return value;
|
||||
null_value=1;
|
||||
return 0.0;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class Item_func_exp :public Item_dec_func
|
||||
|
@ -1,42 +0,0 @@
|
||||
/* Copyright (C) 2000-2001 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/* Fix that we got POSTFIX_ERROR when doing unreasonable math (not core) */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* Fix that we gets POSTFIX_ERROR when error in math */
|
||||
|
||||
#if defined(HAVE_MATHERR)
|
||||
int matherr(struct exception *x)
|
||||
{
|
||||
if (x->type != PLOSS)
|
||||
x->retval=POSTFIX_ERROR;
|
||||
switch (x->type) {
|
||||
case DOMAIN:
|
||||
case SING:
|
||||
my_errno=EDOM;
|
||||
break;
|
||||
case OVERFLOW:
|
||||
case UNDERFLOW:
|
||||
my_errno=ERANGE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return(1); /* Take no other action */
|
||||
}
|
||||
#endif
|
@ -108,7 +108,6 @@
|
||||
|
||||
#define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
|
||||
#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */
|
||||
#define POSTFIX_ERROR DBL_MAX
|
||||
|
||||
#define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH)
|
||||
#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)
|
||||
|
Loading…
x
Reference in New Issue
Block a user