summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysql.cc4
-rw-r--r--include/m_string.h2
-rw-r--r--mysql-test/mysql-test-run.sh3
-rw-r--r--mysql-test/r/ps_1general.result1
-rw-r--r--mysql-test/r/type_float.result34
-rw-r--r--mysql-test/t/mysql_client_test.test7
-rw-r--r--mysql-test/t/ps_1general.test1
-rw-r--r--mysql-test/t/type_float.test26
-rw-r--r--sql/field.cc14
-rw-r--r--sql/item.cc11
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_strfunc.cc3
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/item_sum.h6
-rw-r--r--sql/procedure.h11
-rw-r--r--strings/ctype-simple.c27
-rw-r--r--strings/ctype-ucs2.c9
-rw-r--r--strings/strtod.c167
19 files changed, 239 insertions, 103 deletions
diff --git a/client/mysql.cc b/client/mysql.cc
index 4004757359b..1bbab75434c 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -2914,9 +2914,9 @@ com_status(String *buffer __attribute__((unused)),
MYSQL_ROW cur=mysql_fetch_row(result);
if (cur)
{
- tee_fprintf(stdout, "Server characterset:\t%s\n", cur[0] ? cur[2] : "");
+ tee_fprintf(stdout, "Server characterset:\t%s\n", cur[2] ? cur[2] : "");
tee_fprintf(stdout, "Db characterset:\t%s\n", cur[3] ? cur[3] : "");
- tee_fprintf(stdout, "Client characterset:\t%s\n", cur[2] ? cur[0] : "");
+ tee_fprintf(stdout, "Client characterset:\t%s\n", cur[0] ? cur[0] : "");
tee_fprintf(stdout, "Conn. characterset:\t%s\n", cur[1] ? cur[1] : "");
}
mysql_free_result(result);
diff --git a/include/m_string.h b/include/m_string.h
index 97d34421537..d3465363beb 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -215,7 +215,7 @@ extern char *strstr(const char *, const char *);
extern int is_prefix(const char *, const char *);
/* Conversion routines */
-double my_strtod(const char *str, char **end);
+double my_strtod(const char *str, char **end, int *error);
double my_atof(const char *nptr);
extern char *llstr(longlong value,char *buff);
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index af432f37868..8c484d2ddb1 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -444,6 +444,7 @@ while test $# -gt 0; do
--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqldump.trace"
EXTRA_MYSQLBINLOG_OPT="$EXTRA_MYSQLBINLOG_OPT \
--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysqlbinlog.trace"
+ EXTRA_MYSQL_CLIENT_TEST_OPT="--debug=d:t:A,$MYSQL_TEST_DIR/var/log/mysql_client_test.trace"
;;
--fast)
FAST_START=1
@@ -681,7 +682,7 @@ then
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --user=root"
fi
-MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent"
+MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT --silent $EXTRA_MYSQL_CLIENT_TEST_OPT"
MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT"
MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_OPT"
MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose"
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index 2356989eaf6..ec4aa528a7f 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -1,5 +1,6 @@
drop table if exists t5, t6, t7, t8;
drop database if exists mysqltest ;
+drop database if exists client_test_db;
test_sequence
------ basic tests ------
drop table if exists t1, t9 ;
diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result
index 1f5a34917d7..c1cefe4b35d 100644
--- a/mysql-test/r/type_float.result
+++ b/mysql-test/r/type_float.result
@@ -1,4 +1,4 @@
-drop table if exists t1;
+drop table if exists t1,t2;
SELECT 10,10.0,10.,.1e+2,100.0e-1;
10 10.0 10. .1e+2 100.0e-1
10 10.0 10 10 10
@@ -8,6 +8,15 @@ SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000;
SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1;
1e1 1.e1 1.0e1 1e+1 1.e+1 1.0e+1 1e-1 1.e-1 1.0e-1
10 10 10 10 10 10 0.1 0.1 0.1
+SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01;
+0.001e+1 0.001e-1 -0.001e+01 -0.001e-01
+0.01 0.0001 -0.01 -0.0001
+SELECT 123.23E+02,-123.23E-02,"123.23E+02"+0.0,"-123.23E-02"+0.0;
+123.23E+02 -123.23E-02 "123.23E+02"+0.0 "-123.23E-02"+0.0
+12323 -1.2323 12323 -1.2323
+SELECT 2147483647E+02,21474836.47E+06;
+2147483647E+02 21474836.47E+06
+214748364700 21474836470000
create table t1 (f1 float(24),f2 float(52));
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
@@ -139,6 +148,9 @@ create table t1 (c20 char);
insert into t1 values (5000.0);
Warnings:
Warning 1265 Data truncated for column 'c20' at row 1
+insert into t1 values (0.5e4);
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
drop table t1;
create table t1 (f float(54));
ERROR 42000: Incorrect column specifier for column 'f'
@@ -203,3 +215,23 @@ c
0.0002
2e-05
drop table t1;
+CREATE TABLE t1 (
+reckey int unsigned NOT NULL,
+recdesc varchar(50) NOT NULL,
+PRIMARY KEY (reckey)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES (108, 'Has 108 as key');
+INSERT INTO t1 VALUES (109, 'Has 109 as key');
+select * from t1 where reckey=108;
+reckey recdesc
+108 Has 108 as key
+select * from t1 where reckey=1.08E2;
+reckey recdesc
+108 Has 108 as key
+select * from t1 where reckey=109;
+reckey recdesc
+109 Has 109 as key
+select * from t1 where reckey=1.09E2;
+reckey recdesc
+109 Has 109 as key
+drop table t1;
diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test
index 86aecf43cbd..3639fc2e262 100644
--- a/mysql-test/t/mysql_client_test.test
+++ b/mysql-test/t/mysql_client_test.test
@@ -1,3 +1,10 @@
# We run with different binaries for normal and --embedded-server
+#
+# If this test fails with "command "$MYSQL_CLIENT_TEST" failed",
+# you should either run mysql_client_test separartely against a running
+# server or run mysql-test-run --debug mysql_client_test and check
+# var/log/mysql_client_test.trace
+
--disable_result_log
+--exec echo $MYSQL_CLIENT_TEST
--exec $MYSQL_CLIENT_TEST
diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test
index 4ab81dfcac5..b3ce6d7fd82 100644
--- a/mysql-test/t/ps_1general.test
+++ b/mysql-test/t/ps_1general.test
@@ -11,6 +11,7 @@
--disable_warnings
drop table if exists t5, t6, t7, t8;
drop database if exists mysqltest ;
+drop database if exists client_test_db;
--enable_warnings
--disable_query_log
diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test
index 5b106d242de..6e991dc53d4 100644
--- a/mysql-test/t/type_float.test
+++ b/mysql-test/t/type_float.test
@@ -3,7 +3,7 @@
# Numeric floating point.
--disable_warnings
-drop table if exists t1;
+drop table if exists t1,t2;
--enable_warnings
--replace_result e-0 e- e+0 e+
@@ -11,6 +11,9 @@ SELECT 10,10.0,10.,.1e+2,100.0e-1;
--replace_result e-00 e-0
SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000;
SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1;
+SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01;
+SELECT 123.23E+02,-123.23E-02,"123.23E+02"+0.0,"-123.23E-02"+0.0;
+SELECT 2147483647E+02,21474836.47E+06;
create table t1 (f1 float(24),f2 float(52));
show full columns from t1;
@@ -83,6 +86,7 @@ drop table t1;
#
create table t1 (c20 char);
insert into t1 values (5000.0);
+insert into t1 values (0.5e4);
drop table t1;
# Errors
@@ -120,3 +124,23 @@ create table t1 (c char(6));
insert into t1 values (2e5),(2e6),(2e-4),(2e-5);
select * from t1;
drop table t1;
+
+#
+# Test of comparison of integer with float-in-range (Bug #7840)
+# This is needed because some ODBC applications (like Foxpro) uses
+# floats for everything.
+#
+
+CREATE TABLE t1 (
+ reckey int unsigned NOT NULL,
+ recdesc varchar(50) NOT NULL,
+ PRIMARY KEY (reckey)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+
+INSERT INTO t1 VALUES (108, 'Has 108 as key');
+INSERT INTO t1 VALUES (109, 'Has 109 as key');
+select * from t1 where reckey=108;
+select * from t1 where reckey=1.08E2;
+select * from t1 where reckey=109;
+select * from t1 where reckey=1.09E2;
+drop table t1;
diff --git a/sql/field.cc b/sql/field.cc
index fa0e202d513..ca923d723bc 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -968,7 +968,9 @@ int Field_decimal::store(longlong nr)
double Field_decimal::val_real(void)
{
int not_used;
- return my_strntod(&my_charset_bin, ptr, field_length, NULL, &not_used);
+ char *end_not_used;
+ return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used,
+ &not_used);
}
longlong Field_decimal::val_int(void)
@@ -4360,8 +4362,9 @@ int Field_string::store(longlong nr)
double Field_string::val_real(void)
{
int not_used;
+ char *end_not_used;
CHARSET_INFO *cs=charset();
- return my_strntod(cs,ptr,field_length,(char**)0,&not_used);
+ return my_strntod(cs, ptr, field_length, &end_not_used, &not_used);
}
@@ -4577,7 +4580,9 @@ double Field_varstring::val_real(void)
int not_used;
uint length=uint2korr(ptr)+HA_KEY_BLOB_LENGTH;
CHARSET_INFO *cs=charset();
- return my_strntod(cs, ptr+HA_KEY_BLOB_LENGTH, length, (char**)0, &not_used);
+ char *end_not_used;
+ return my_strntod(cs, ptr+HA_KEY_BLOB_LENGTH, length, &end_not_used,
+ &not_used);
}
@@ -4955,12 +4960,13 @@ double Field_blob::val_real(void)
{
int not_used;
char *blob;
+ char *end_not_used;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
uint32 length=get_length(ptr);
CHARSET_INFO *cs=charset();
- return my_strntod(cs,blob,length,(char**)0, &not_used);
+ return my_strntod(cs,blob,length, &end_not_used, &not_used);
}
diff --git a/sql/item.cc b/sql/item.cc
index 4b3acbe5a3c..76cbaa99029 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1140,8 +1140,9 @@ double Item_param::val()
case LONG_DATA_VALUE:
{
int dummy_err;
+ char *end_not_used;
return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), (char**) 0, &dummy_err);
+ str_value.length(), &end_not_used, &dummy_err);
}
case TIME_VALUE:
/*
@@ -2585,10 +2586,12 @@ double Item_cache_str::val()
DBUG_ASSERT(fixed == 1);
int err;
if (value)
+ {
+ char *end_not_used;
return my_strntod(value->charset(), (char*) value->ptr(),
- value->length(), (char**) 0, &err);
- else
- return (double)0;
+ value->length(), &end_not_used, &err);
+ }
+ return (double)0;
}
diff --git a/sql/item.h b/sql/item.h
index dd06d4ce61a..97e2b0c0945 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -719,8 +719,9 @@ public:
{
DBUG_ASSERT(fixed == 1);
int err;
+ char *end_not_used;
return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), (char**) 0, &err);
+ str_value.length(), &end_not_used, &err);
}
longlong val_int()
{
@@ -1044,9 +1045,10 @@ public:
double val()
{
int err;
+ char *end_not_used;
return (null_value ? 0.0 :
my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(),NULL,&err));
+ str_value.length(), &end_not_used, &err));
}
longlong val_int()
{
diff --git a/sql/item_func.h b/sql/item_func.h
index 8a5347d675e..2738c7419ca 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -828,8 +828,11 @@ public:
double val()
{
int err;
- String *res; res=val_str(&str_value);
- return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),0,&err) : 0.0;
+ String *res;
+ char *end_not_used;
+ res=val_str(&str_value);
+ return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err) : 0.0;
}
longlong val_int()
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index bbbcadbb071..8bd1da4e15f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -63,10 +63,11 @@ double Item_str_func::val()
DBUG_ASSERT(fixed == 1);
int err;
char buff[64];
+ char *end_not_used;
String *res, tmp(buff,sizeof(buff), &my_charset_bin);
res= val_str(&tmp);
return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
- NULL, &err) : 0.0;
+ &end_not_used, &err) : 0.0;
}
longlong Item_str_func::val_int()
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 029a1fd6c48..6bd2cc00b3e 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -471,13 +471,14 @@ double Item_sum_hybrid::val()
{
DBUG_ASSERT(fixed == 1);
int err;
+ char *end_not_used;
if (null_value)
return 0.0;
switch (hybrid_type) {
case STRING_RESULT:
String *res; res=val_str(&str_value);
return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
- (char**) 0, &err) : 0.0);
+ &end_not_used, &err) : 0.0);
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
diff --git a/sql/item_sum.h b/sql/item_sum.h
index d1e82387944..dab136e4716 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -600,9 +600,11 @@ public:
double val()
{
int err;
- String *res; res=val_str(&str_value);
+ char *end_not_used;
+ String *res;
+ res=val_str(&str_value);
return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),
- (char**) 0, &err) : 0.0;
+ &end_not_used, &err) : 0.0;
}
longlong val_int()
{
diff --git a/sql/procedure.h b/sql/procedure.h
index 5365b2e1102..abe50bdc0a0 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -59,7 +59,11 @@ public:
void set(double nr) { value=nr; }
void set(longlong nr) { value=(double) nr; }
void set(const char *str,uint length,CHARSET_INFO *cs)
- { int err; value=my_strntod(cs,(char*) str,length,(char**)0,&err); }
+ {
+ int err;
+ char *end_not_used;
+ value= my_strntod(cs, (char*) str, length, &end_not_used, &err);
+ }
double val() { return value; }
longlong val_int() { return (longlong) value; }
String *val_str(String *s) { s->set(value,decimals,default_charset()); return s; }
@@ -99,9 +103,10 @@ public:
double val()
{
int err;
- CHARSET_INFO *cs=str_value.charset();
+ CHARSET_INFO *cs= str_value.charset();
+ char *end_not_used;
return my_strntod(cs, (char*) str_value.ptr(), str_value.length(),
- (char**) 0, &err);
+ &end_not_used, &err);
}
longlong val_int()
{
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 1a09b16a264..c2a6aa4e17f 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -773,31 +773,10 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)),
char *str, uint length,
char **end, int *err)
{
- char end_char;
- double result;
-
- errno= 0; /* Safety */
-
- /*
- The following define is to avoid warnings from valgrind as str[length]
- may not be defined (which is not fatal in real life)
- */
-
-#ifdef HAVE_purify
if (length == INT_MAX32)
-#else
- if (length == INT_MAX32 || str[length] == 0)
-#endif
- result= my_strtod(str, end);
- else
- {
- end_char= str[length];
- str[length]= 0;
- result= my_strtod(str, end);
- str[length]= end_char; /* Restore end char */
- }
- *err= errno;
- return result;
+ length= 65535; /* Should be big enough */
+ *end= str + length;
+ return my_strtod(str, end, err);
}
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index e92704b83d7..9c67d1b7846 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -946,13 +946,10 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
break; /* Can't be part of double */
*b++= (char) wc;
}
- *b= 0;
- errno= 0;
- res=my_strtod(buf, endptr);
- *err= errno;
- if (endptr)
- *endptr=(char*) (*endptr-buf+nptr);
+ *endptr= b;
+ res= my_strtod(buf, endptr, err);
+ *endptr= nptr + (uint) (*endptr- buf);
return res;
}
diff --git a/strings/strtod.c b/strings/strtod.c
index bc8105b8040..61f2c107abe 100644
--- a/strings/strtod.c
+++ b/strings/strtod.c
@@ -2,7 +2,7 @@
An alternative implementation of "strtod()" that is both
simplier, and thread-safe.
- From mit-threads as bundled with MySQL 3.23
+ Original code from mit-threads as bundled with MySQL 3.23
SQL:2003 specifies a number as
@@ -29,6 +29,8 @@
#include "my_base.h" /* Includes errno.h */
#include "m_ctype.h"
+#define MAX_DBL_EXP 308
+#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232
static double scaler10[] = {
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
};
@@ -37,89 +39,157 @@ static double scaler1[] = {
};
-double my_strtod(const char *str, char **end)
+/*
+ Convert string to double (string doesn't have to be null terminated)
+
+ SYNOPSIS
+ my_strtod()
+ str String to convert
+ end_ptr Pointer to pointer that points to end of string
+ Will be updated to point to end of double.
+ error Will contain error number in case of error (else 0)
+
+ RETURN
+ value of str as double
+*/
+
+double my_strtod(const char *str, char **end_ptr, int *error)
{
double result= 0.0;
- int negative, ndigits;
- const char *old_str;
+ uint negative= 0, ndigits, dec_digits= 0, neg_exp= 0;
+ int exp= 0, digits_after_dec_point= 0;
+ const char *old_str, *end= *end_ptr, *start_of_number;
+ char next_char;
my_bool overflow=0;
+ *error= 0;
+ if (str >= end)
+ goto done;
+
while (my_isspace(&my_charset_latin1, *str))
- str++;
+ {
+ if (++str == end)
+ goto done;
+ }
+ start_of_number= str;
if ((negative= (*str == '-')) || *str=='+')
- str++;
+ {
+ if (++str == end)
+ goto done; /* Could be changed to error */
+ }
+
+ /* Skip pre-zero for easier calculation of overflows */
+ while (*str == '0')
+ {
+ if (++str == end)
+ goto done;
+ start_of_number= 0; /* Found digit */
+ }
old_str= str;
- while (my_isdigit (&my_charset_latin1, *str))
+ while ((next_char= *str) >= '0' && next_char <= '9')
{
- result= result*10.0 + (*str - '0');
- str++;
+ result= result*10.0 + (next_char - '0');
+ if (++str == end)
+ {
+ next_char= 0; /* Found end of string */
+ break;
+ }
+ start_of_number= 0; /* Found digit */
}
- ndigits= str-old_str;
+ ndigits= (uint) (str-old_str);
- if (*str == '.')
+ if (next_char == '.' && str < end-1)
{
- double p10=10;
- str++;
- old_str= str;
- while (my_isdigit (&my_charset_latin1, *str))
+ /*
+ Continue to add numbers after decimal point to the result, as if there
+ was no decimal point. We will later (in the exponent handling) shift
+ the number down with the required number of fractions. We do it this
+ way to be able to get maximum precision for numbers like 123.45E+02,
+ which are normal for some ODBC applications.
+ */
+ old_str= ++str;
+ while (my_isdigit(&my_charset_latin1, (next_char= *str)))
{
- result+= (*str++ - '0')/p10;
- p10*=10;
+ result= result*10.0 + (next_char - '0');
+ digits_after_dec_point++;
+ if (++str == end)
+ {
+ next_char= 0;
+ break;
+ }
}
- ndigits+= str-old_str;
- if (!ndigits) str--;
+ /* If we found just '+.' or '.' then point at first character */
+ if (!(dec_digits= (uint) (str-old_str)) && start_of_number)
+ str= start_of_number; /* Point at '+' or '.' */
}
- if (ndigits && (*str=='e' || *str=='E'))
+ if ((next_char == 'e' || next_char == 'E') &&
+ dec_digits + ndigits != 0 && str < end-1)
{
- int exp= 0;
- int neg= 0;
const char *old_str= str++;
- if ((neg= (*str == '-')) || *str == '+')
+ if ((neg_exp= (*str == '-')) || *str == '+')
str++;
- if (!my_isdigit (&my_charset_latin1, *str))
+ if (str == end || !my_isdigit(&my_charset_latin1, *str))
str= old_str;
else
{
- double scaler= 1.0;
- while (my_isdigit (&my_charset_latin1, *str))
+ do
{
- if (exp < 9999) /* protection against exp overflow */
- exp= exp*10 + *str - '0';
+ if (exp < 9999) /* prot. against exp overfl. */
+ exp= exp*10 + (*str - '0');
str++;
- }
- if (exp >= 1000)
+ } while (str < end && my_isdigit(&my_charset_latin1, *str));
+ }
+ }
+ if ((exp= (neg_exp ? exp + digits_after_dec_point :
+ exp - digits_after_dec_point)))
+ {
+ double scaler;
+ if (exp < 0)
+ {
+ exp= -exp;
+ neg_exp= 1; /* neg_exp was 0 before */
+ }
+ if (exp + ndigits >= MAX_DBL_EXP + 1 && result)
+ {
+ /*
+ This is not 100 % as we actually will give an owerflow for
+ 17E307 but not for 1.7E308 but lets cut some corners to make life
+ simpler
+ */
+ if (exp + ndigits > MAX_DBL_EXP + 1 ||
+ result >= MAX_RESULT_FOR_MAX_EXP)
{
- if (neg)
- result= 0.0;
- else
+ if (neg_exp)
+ result= 0.0;
+ else
overflow= 1;
goto done;
}
- while (exp >= 100)
- {
- scaler*= 1.0e100;
- exp-= 100;
- }
- scaler*= scaler10[exp/10]*scaler1[exp%10];
- if (neg)
- result/= scaler;
- else
- result*= scaler;
}
+ scaler= 1.0;
+ while (exp >= 100)
+ {
+ scaler*= 1.0e100;
+ exp-= 100;
+ }
+ scaler*= scaler10[exp/10]*scaler1[exp%10];
+ if (neg_exp)
+ result/= scaler;
+ else
+ result*= scaler;
}
done:
- if (end)
- *end = (char *)str;
+ *end_ptr= (char*) str; /* end of number */
if (overflow || isinf(result))
{
result= DBL_MAX;
- errno= EOVERFLOW;
+ *error= EOVERFLOW;
}
return negative ? -result : result;
@@ -127,6 +197,7 @@ done:
double my_atof(const char *nptr)
{
- return (my_strtod(nptr, 0));
+ int error;
+ const char *end= nptr+65535; /* Should be enough */
+ return (my_strtod(nptr, (char**) &end, &error));
}
-