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.*)
|
*hpux11.*)
|
||||||
AC_MSG_WARN([Enabling workarounds for hpux 11])
|
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"
|
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 -DDONT_USE_FINITE -D_INCLUDE_LONGLONG -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"
|
if test "$with_named_thread" = "no"
|
||||||
then
|
then
|
||||||
AC_MSG_WARN([Using --with-named-thread=-lpthread])
|
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 !!! */
|
#include <sys/stream.h> /* HPUX 10.20 defines ulong here. UGLY !!! */
|
||||||
#define HAVE_ULONG
|
#define HAVE_ULONG
|
||||||
#endif
|
#endif
|
||||||
#ifdef DONT_USE_FINITE /* HPUX 11.x has is_finite() */
|
|
||||||
#undef HAVE_FINITE
|
|
||||||
#endif
|
|
||||||
#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) && defined(THREAD)
|
#if defined(HPUX10) && defined(_LARGEFILE64_SOURCE) && defined(THREAD)
|
||||||
/* Fix bug in setrlimit */
|
/* Fix bug in setrlimit */
|
||||||
#undef setrlimit
|
#undef setrlimit
|
||||||
@ -858,9 +855,13 @@ typedef SOCKET_SIZE_TYPE size_socket;
|
|||||||
#define SIZE_T_MAX ~((size_t) 0)
|
#define SIZE_T_MAX ~((size_t) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_FINITE
|
#ifndef isfinite
|
||||||
|
#ifdef HAVE_FINITE
|
||||||
|
#define isfinite(x) finite(x)
|
||||||
|
#else
|
||||||
#define finite(x) (1.0 / fabs(x) > 0.0)
|
#define finite(x) (1.0 / fabs(x) > 0.0)
|
||||||
#endif
|
#endif /* HAVE_FINITE */
|
||||||
|
#endif /* isfinite */
|
||||||
|
|
||||||
#ifndef HAVE_ISNAN
|
#ifndef HAVE_ISNAN
|
||||||
#define isnan(x) ((x) != (x))
|
#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 */
|
/* isinf() can be used in both C and C++ code */
|
||||||
#define my_isinf(X) isinf(X)
|
#define my_isinf(X) isinf(X)
|
||||||
#else
|
#else
|
||||||
#define my_isinf(X) (!finite(X) && !isnan(X))
|
#define my_isinf(X) (!isfinite(X) && !isnan(X))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Define missing math constants. */
|
/* Define missing math constants. */
|
||||||
|
@ -408,3 +408,22 @@ a DIV 2
|
|||||||
0
|
0
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
End of 5.0 tests
|
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');
|
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
|
||||||
ERROR 22003: Out of range value for column 'col2' at row 1
|
ERROR 22003: Out of range value for column 'col2' at row 1
|
||||||
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
|
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;
|
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
|
||||||
ERROR 22012: Division by 0
|
ERROR 22012: Division by 0
|
||||||
UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
|
UPDATE t1 SET col2= MOD(col2,0) WHERE col2 > 0;
|
||||||
@ -923,10 +922,10 @@ SELECT * FROM t1;
|
|||||||
col1 col2
|
col1 col2
|
||||||
-2.2e-307 0
|
-2.2e-307 0
|
||||||
1e-303 0
|
1e-303 0
|
||||||
1.7e+308 1.7e+308
|
NULL 1.7e+308
|
||||||
-2.2e-307 0
|
-2.2e-307 0
|
||||||
-2e-307 0
|
-2e-307 0
|
||||||
1.7e+308 1.7e+308
|
NULL 1.7e+308
|
||||||
0 NULL
|
0 NULL
|
||||||
2 NULL
|
2 NULL
|
||||||
NULL 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;
|
SELECT a DIV 2 FROM t1 UNION SELECT a DIV 2 FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
--echo End of 5.0 tests
|
--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');
|
INSERT INTO t1 (col1) VALUES ('+1.8E+309');
|
||||||
--error 1264
|
--error 1264
|
||||||
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
|
INSERT INTO t1 (col2) VALUES ('-1.2E-3');
|
||||||
--error 1264
|
|
||||||
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
|
UPDATE t1 SET col1 =col1 * 5000 WHERE col1 > 0;
|
||||||
--error 1365
|
--error 1365
|
||||||
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
|
UPDATE t1 SET col2 =col2 / 0 WHERE col2 > 0;
|
||||||
|
@ -2263,13 +2263,11 @@ int Field_decimal::store(double nr)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FINITE
|
if (!isfinite(nr)) // Handle infinity as special case
|
||||||
if (!finite(nr)) // Handle infinity as special case
|
|
||||||
{
|
{
|
||||||
overflow(nr < 0.0);
|
overflow(nr < 0.0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
reg4 uint i;
|
reg4 uint i;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
@ -1104,7 +1104,7 @@ double Item_func_plus::real_op()
|
|||||||
double value= args[0]->val_real() + args[1]->val_real();
|
double value= args[0]->val_real() + args[1]->val_real();
|
||||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||||
return 0.0;
|
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();
|
double value= args[0]->val_real() - args[1]->val_real();
|
||||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||||
return 0.0;
|
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();
|
double value= args[0]->val_real() * args[1]->val_real();
|
||||||
if ((null_value=args[0]->null_value || args[1]->null_value))
|
if ((null_value=args[0]->null_value || args[1]->null_value))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return value;
|
return fix_result(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1282,7 +1282,7 @@ double Item_func_div::real_op()
|
|||||||
signal_divide_by_null();
|
signal_divide_by_null();
|
||||||
return 0.0;
|
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();
|
double value= args[0]->val_real();
|
||||||
if ((null_value=args[0]->null_value))
|
if ((null_value=args[0]->null_value))
|
||||||
return 0.0; /* purecov: inspected */
|
return 0.0; /* purecov: inspected */
|
||||||
return exp(value);
|
return fix_result(exp(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_sqrt::val_real()
|
double Item_func_sqrt::val_real()
|
||||||
@ -1674,7 +1674,7 @@ double Item_func_pow::val_real()
|
|||||||
double val2= args[1]->val_real();
|
double val2= args[1]->val_real();
|
||||||
if ((null_value=(args[0]->null_value || args[1]->null_value)))
|
if ((null_value=(args[0]->null_value || args[1]->null_value)))
|
||||||
return 0.0; /* purecov: inspected */
|
return 0.0; /* purecov: inspected */
|
||||||
return pow(value,val2);
|
return fix_result(pow(value,val2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigonometric functions
|
// Trigonometric functions
|
||||||
@ -1686,7 +1686,7 @@ double Item_func_acos::val_real()
|
|||||||
volatile double value= args[0]->val_real();
|
volatile double value= args[0]->val_real();
|
||||||
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return fix_result(acos(value));
|
return acos(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_asin::val_real()
|
double Item_func_asin::val_real()
|
||||||
@ -1696,7 +1696,7 @@ double Item_func_asin::val_real()
|
|||||||
volatile double value= args[0]->val_real();
|
volatile double value= args[0]->val_real();
|
||||||
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0))))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return fix_result(asin(value));
|
return asin(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_atan::val_real()
|
double Item_func_atan::val_real()
|
||||||
@ -1712,7 +1712,7 @@ double Item_func_atan::val_real()
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
return fix_result(atan2(value,val2));
|
return fix_result(atan2(value,val2));
|
||||||
}
|
}
|
||||||
return fix_result(atan(value));
|
return atan(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_cos::val_real()
|
double Item_func_cos::val_real()
|
||||||
@ -1721,7 +1721,7 @@ double Item_func_cos::val_real()
|
|||||||
double value= args[0]->val_real();
|
double value= args[0]->val_real();
|
||||||
if ((null_value=args[0]->null_value))
|
if ((null_value=args[0]->null_value))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return fix_result(cos(value));
|
return cos(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_sin::val_real()
|
double Item_func_sin::val_real()
|
||||||
@ -1730,7 +1730,7 @@ double Item_func_sin::val_real()
|
|||||||
double value= args[0]->val_real();
|
double value= args[0]->val_real();
|
||||||
if ((null_value=args[0]->null_value))
|
if ((null_value=args[0]->null_value))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
return fix_result(sin(value));
|
return sin(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Item_func_tan::val_real()
|
double Item_func_tan::val_real()
|
||||||
|
@ -192,6 +192,13 @@ public:
|
|||||||
void * arg, traverse_order order);
|
void * arg, traverse_order order);
|
||||||
bool is_expensive_processor(uchar *arg);
|
bool is_expensive_processor(uchar *arg);
|
||||||
virtual bool is_expensive() { return 0; }
|
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);
|
decimals=NOT_FIXED_DEC; max_length=float_length(decimals);
|
||||||
maybe_null=1;
|
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
|
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 READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
|
||||||
#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */
|
#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_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH)
|
||||||
#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)
|
#define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user