summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/compile-solaris-sparc-purify23
-rw-r--r--include/m_string.h2
-rw-r--r--mysql-test/mysql-test-run.sh16
-rw-r--r--mysql-test/r/strict.result2
-rw-r--r--mysql-test/r/type_float.result5
-rw-r--r--mysql-test/t/strict.test2
-rw-r--r--mysql-test/t/type_float.test3
-rw-r--r--mysys/mf_iocache.c13
-rw-r--r--mysys/thr_lock.c6
-rw-r--r--sql/field.cc29
-rw-r--r--sql/filesort.cc5
-rw-r--r--sql/item.cc24
-rw-r--r--sql/item_strfunc.cc10
-rw-r--r--sql/item_sum.cc9
-rw-r--r--strings/ctype-cp932.c6
-rw-r--r--strings/ctype-simple.c27
-rw-r--r--strings/ctype-ucs2.c18
-rw-r--r--strings/strtod.c162
18 files changed, 219 insertions, 143 deletions
diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify
index 71a60e45cb0..c895d99c2cf 100755
--- a/BUILD/compile-solaris-sparc-purify
+++ b/BUILD/compile-solaris-sparc-purify
@@ -3,28 +3,27 @@
while test $# -gt 0
do
case "$1" in
- --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;;
- -h | --help ) cat <<EOF; exit 0 ;;
-Usage: $0 [-h|-n] [configure-options]
- --debug Compile with DBUG enabled
-EOF
- *) echo "No such option '$1'" ; exit ;;
+ --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;;
+ -h | --help )
+ echo "Usage: $0 [-h|-n] [configure-options]"
+ echo " --debug Compile with DBUG enabled"
+ exit 0 ;;
+ *) echo "No such option '$1'" ; exit ;;
esac
done
gmake -k clean || true
/bin/rm -f */.deps/*.P config.cache
aclocal && autoheader && aclocal && automake && autoconf
-(cd bdb/dist && sh s_all)
+# (cd bdb/dist && sh s_all)
(cd innobase && aclocal && autoheader && aclocal && automake && autoconf)
-CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-innodb $EXTRA_CONFIG_FLAGS
+CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --without-berkeley-db --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS
gmake -j 4
cd sql ; mv mysqld mysqld-org ;
-make CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify
-make CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify
-make CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov
+gmake CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify
+gmake CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify
+gmake CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov
mv mysqld-org mysqld
-
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 274f91550d4..ea41e847c2c 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -427,6 +427,9 @@ while test $# -gt 0; do
--fast)
FAST_START=1
;;
+ --use-old-data)
+ USE_OLD_DATA=1;
+ ;;
-- ) shift; break ;;
--* ) $ECHO "Unrecognized option: $1"; exit 1 ;;
* ) break ;;
@@ -768,12 +771,14 @@ report_stats () {
mysql_install_db () {
$ECHO "Removing Stale Files"
- $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1" $SLAVE_MYDDIR $MY_LOG_DIR/*
- $ECHO "Installing Master Databases"
- $INSTALL_DB
- if [ $? != 0 ]; then
+ if [ -z "$USE_OLD_DATA" ]; then
+ $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1"
+ $ECHO "Installing Master Databases"
+ $INSTALL_DB
+ if [ $? != 0 ]; then
error "Could not install master test DBs"
- exit 1
+ exit 1
+ fi
fi
if [ ! -z "$USE_NDBCLUSTER" ]
then
@@ -785,6 +790,7 @@ mysql_install_db () {
fi
fi
$ECHO "Installing Slave Databases"
+ $RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/*
$INSTALL_DB -slave
if [ $? != 0 ]; then
error "Could not install slave test DBs"
diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result
index fb228d37da3..f28317ce947 100644
--- a/mysql-test/r/strict.result
+++ b/mysql-test/r/strict.result
@@ -768,7 +768,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308);
INSERT INTO t1 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308');
INSERT INTO t1 (col1) VALUES (-2.2E-330);
INSERT INTO t1 (col1) VALUES (+1.7E+309);
-ERROR 22007: Illegal double '1.7E+309' value found during parsing
+Got one of the listed errors
INSERT INTO t1 (col2) VALUES (-1.1E-3);
ERROR 22003: Out of range value adjusted for column 'col2' at row 1
INSERT INTO t1 (col1) VALUES ('+1.8E+309');
diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result
index 62aae177f6a..26cfbdeffd0 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,9 @@ 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
create table t1 (f1 float(24),f2 float(52));
show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment
diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test
index a0cfc0c60f4..2ccc3e672c7 100644
--- a/mysql-test/t/strict.test
+++ b/mysql-test/t/strict.test
@@ -531,7 +531,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308);
INSERT INTO t1 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308');
# We don't give warnings for underflow
INSERT INTO t1 (col1) VALUES (-2.2E-330);
---error 1367
+--error 1367,1264
INSERT INTO t1 (col1) VALUES (+1.7E+309);
--error 1264
INSERT INTO t1 (col2) VALUES (-1.1E-3);
diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test
index 3fe3afa3fac..913034dac0e 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,7 @@ 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;
create table t1 (f1 float(24),f2 float(52));
show full columns from t1;
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index f109df912f1..7466ae24675 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -27,7 +27,7 @@
also info->read_pos is set to info->read_end.
If called through open_cached_file(), then the temporary file will
only be created if a write exeeds the file buffer or if one calls
- flush_io_cache().
+ my_b_flush_io_cache().
If one uses SEQ_READ_APPEND, then two buffers are allocated, one for
reading and another for writing. Reads are first done from disk and
@@ -43,7 +43,7 @@ TODO:
each time the write buffer gets full and it's written to disk, we will
always do a disk read to read a part of the buffer from disk to the
read buffer.
- This should be fixed so that when we do a flush_io_cache() and
+ This should be fixed so that when we do a my_b_flush_io_cache() and
we have been reading the write buffer, we should transfer the rest of the
write buffer to the read buffer before we start to reuse it.
*/
@@ -339,7 +339,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
if (info->type == WRITE_CACHE && type == READ_CACHE)
info->end_of_file=my_b_tell(info);
/* flush cache if we want to reuse it */
- if (!clear_cache && flush_io_cache(info))
+ if (!clear_cache && my_b_flush_io_cache(info,1))
DBUG_RETURN(1);
info->pos_in_file=seek_offset;
/* Better to do always do a seek */
@@ -948,7 +948,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer+=rest_length;
Count-=rest_length;
info->write_pos+=rest_length;
- if (flush_io_cache(info))
+ if (my_b_flush_io_cache(info,1))
return 1;
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
@@ -1191,6 +1191,7 @@ int end_io_cache(IO_CACHE *info)
int error=0;
IO_CACHE_CALLBACK pre_close;
DBUG_ENTER("end_io_cache");
+ DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info));
#ifdef THREAD
/*
@@ -1200,7 +1201,7 @@ int end_io_cache(IO_CACHE *info)
*/
if (info->share)
{
- pthread_cond_destroy (&info->share->cond);
+ pthread_cond_destroy(&info->share->cond);
pthread_mutex_destroy(&info->share->mutex);
info->share=0;
}
@@ -1215,7 +1216,7 @@ int end_io_cache(IO_CACHE *info)
{
info->alloced_buffer=0;
if (info->file != -1) /* File doesn't exist */
- error=flush_io_cache(info);
+ error= my_b_flush_io_cache(info,1);
my_free((gptr) info->buffer,MYF(MY_WME));
info->buffer=info->read_pos=(byte*) 0;
}
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index d47ca8de183..9ce058f90fc 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -523,8 +523,10 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type)
data->prev=lock->write_wait.last;
lock->write_wait.last= &data->next;
data->cond=get_cond();
- if (lock->get_status)
- (*lock->get_status)(data->status_param);
+ /*
+ We don't have to do get_status here as we will do it when we change
+ the delayed lock to a real write lock
+ */
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
diff --git a/sql/field.cc b/sql/field.cc
index 175ca09df37..29125d9d655 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1035,7 +1035,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)
@@ -4425,16 +4427,18 @@ int Field_string::store(longlong nr)
double Field_string::val_real(void)
{
int not_used;
- CHARSET_INFO *cs=charset();
- return my_strntod(cs,ptr,field_length,(char**)0,&not_used);
+ char *end_not_used;
+ CHARSET_INFO *cs= charset();
+ return my_strntod(cs,ptr,field_length,&end_not_used,&not_used);
}
longlong Field_string::val_int(void)
{
int not_used;
+ char *end_not_used;
CHARSET_INFO *cs=charset();
- return my_strntoll(cs,ptr,field_length,10,NULL,&not_used);
+ return my_strntoll(cs,ptr,field_length,10,&end_not_used,&not_used);
}
@@ -4734,8 +4738,9 @@ int Field_varstring::store(longlong nr)
double Field_varstring::val_real(void)
{
int not_used;
+ char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntod(field_charset, ptr+length_bytes, length, (char**) 0,
+ return my_strntod(field_charset, ptr+length_bytes, length, &end_not_used,
&not_used);
}
@@ -4743,9 +4748,10 @@ double Field_varstring::val_real(void)
longlong Field_varstring::val_int(void)
{
int not_used;
+ char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
- return my_strntoll(field_charset, ptr+length_bytes, length, 10, NULL,
- &not_used);
+ return my_strntoll(field_charset, ptr+length_bytes, length, 10,
+ &end_not_used, &not_used);
}
@@ -5339,12 +5345,15 @@ int Field_blob::store(longlong nr)
double Field_blob::val_real(void)
{
int not_used;
- char *blob;
+ char *end_not_used, *blob;
+ uint32 length;
+ CHARSET_INFO *cs;
+
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
- uint32 length=get_length(ptr);
- CHARSET_INFO *cs=charset();
+ length= get_length(ptr);
+ cs= charset();
return my_strntod(cs,blob,length,(char**)0, &not_used);
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 0a4e747a136..b79ea6515c3 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -567,10 +567,10 @@ write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
if (!my_b_inited(tempfile) &&
open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE,
MYF(MY_WME)))
- goto err; /* purecov: inspected */
+ goto err; /* purecov: inspected */
buffpek.file_pos= my_b_tell(tempfile);
if ((ha_rows) count > param->max_rows)
- count=(uint) param->max_rows; /* purecov: inspected */
+ count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length))
@@ -844,6 +844,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
if (flush_io_cache(to_file))
break; /* purecov: inspected */
temp=from_file; from_file=to_file; to_file=temp;
+
*maxbuffer= (uint) (lastbuff-buffpek)-1;
}
close_cached_file(to_file); // This holds old result
diff --git a/sql/item.cc b/sql/item.cc
index c84496f8eb7..47dccf5b8da 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1290,11 +1290,12 @@ double Item_param::val_real()
return (double) value.integer;
case STRING_VALUE:
case LONG_DATA_VALUE:
- {
- int dummy_err;
- return my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), (char**) 0, &dummy_err);
- }
+ {
+ int dummy_err;
+ char *end_not_used;
+ return my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), &end_not_used, &dummy_err);
+ }
case TIME_VALUE:
/*
This works for example when user says SELECT ?+0.0 and supplies
@@ -2545,8 +2546,9 @@ Item_num *Item_uint::neg()
Item_real::Item_real(const char *str_arg, uint length)
{
int error;
- char *end;
- value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end, &error);
+ char *end_not_used;
+ value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used,
+ &error);
if (error)
{
/*
@@ -3522,12 +3524,12 @@ void Item_cache_str::store(Item *item)
double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
+ int err_not_used;
+ char *end_not_used;
if (value)
return my_strntod(value->charset(), (char*) value->ptr(),
- value->length(), (char**) 0, &err);
- else
- return (double)0;
+ value->length(), &end_not_used, &err_not_used);
+ return (double) 0;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 9e28acdd091..09b6d9cc35d 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -58,17 +58,19 @@ uint nr_of_decimals(const char *str)
return 0;
}
+
double Item_str_func::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
- char buff[64];
+ int err_not_used;
+ char *end_not_used, buff[64];
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;
+ return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0;
}
+
longlong Item_str_func::val_int()
{
DBUG_ASSERT(fixed == 1);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 168c68ad706..be89aa3f86d 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -591,14 +591,17 @@ void Item_sum_hybrid::clear()
double Item_sum_hybrid::val_real()
{
DBUG_ASSERT(fixed == 1);
- int err;
if (null_value)
return 0.0;
switch (hybrid_type) {
case STRING_RESULT:
+ {
+ char *end_not_used;
+ int err_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);
+ return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0);
+ }
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c
index 218fc72ad17..e5429148970 100644
--- a/strings/ctype-cp932.c
+++ b/strings/ctype-cp932.c
@@ -243,8 +243,10 @@ static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)),
- const uchar *a, uint a_length,
- const uchar *b, uint b_length)
+ const uchar *a, uint a_length,
+ const uchar *b, uint b_length,
+ my_bool diff_if_only_endspace_difference
+ __attribute__((unused)))
{
const uchar *a_end= a + a_length;
const uchar *b_end= b + b_length;
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 0659cb5d387..fdfe72864b2 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -750,31 +750,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 d21b340e768..7b9a7ab3020 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -925,15 +925,16 @@ bs:
return (negative ? -((longlong) res) : (longlong) res);
}
-double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
- char *nptr, uint length,
- char **endptr, int *err)
+
+double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
+ char *nptr, uint length,
+ char **endptr, int *err)
{
char buf[256];
double res;
register char *b=buf;
register const uchar *s= (const uchar*) nptr;
- register const uchar *end;
+ const uchar *end;
my_wc_t wc;
int cnv;
@@ -950,13 +951,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..92d93612dd0 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,154 @@ 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, pre_zero, neg_exp= 0;
+ int exp= 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 == '.')
+ pre_zero= 0;
+ if (next_char == '.' && str < end-1)
{
- double p10=10;
- str++;
- old_str= str;
- while (my_isdigit (&my_charset_latin1, *str))
+ double p10= 10;
+ old_str= ++str;
+ while (my_isdigit(&my_charset_latin1, (next_char= *str)))
{
- result+= (*str++ - '0')/p10;
- p10*=10;
+ result+= (next_char - '0')/p10;
+ if (!result)
+ pre_zero++;
+ else
+ p10*= 10;
+ 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 */
+ if (exp < 9999) /* protec 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 + pre_zero : exp - pre_zero))
+ {
+ 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 +194,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));
}
-