Commit 5437a90d authored by unknown's avatar unknown

Changed interface for my_strntod() to make it more general and more portable


BUILD/compile-solaris-sparc-purify:
  Cleanup (Changes from Kent)
include/m_string.h:
  New interface for my_strtod()
mysql-test/mysql-test-run.sh:
  Added option --use-old-data to allow one to run a test case on an existing table
  (Good for debugging)
mysql-test/r/strict.result:
  Updated results
mysql-test/r/type_float.result:
  More tests
mysql-test/t/strict.test:
  Safety fix
mysql-test/t/type_float.test:
  More tests
mysys/mf_iocache.c:
  Change flush_io_cache() to my_b_flush_io_cache()
  More debugging
mysys/thr_lock.c:
  Added comment
sql/field.cc:
  Use new my_strntod()
sql/filesort.cc:
  Indentation fixes
sql/item.cc:
  Use new my_strntod()
sql/item_strfunc.cc:
  Use new my_strntod()
sql/item_sum.cc:
  Use new my_strntod()
strings/ctype-cp932.c:
  strnncollsp was missing one argument
strings/ctype-simple.c:
  Use new my_strntod()
strings/ctype-ucs2.c:
  Use new my_strntod()
strings/strtod.c:
  Changed interface:
  - Force user to supply pointer to end of string (eliminates the need for an end \0)
  - More strict error checking (depend less off if INF is set), which makes this more portable
  - Better handling of numbers of type 0.000000....E+...
  - Return pointer to + in case of '+.'
  
  The above should fix a that strict.test failed on Solaris-sparc.
parent 7222ac50
...@@ -4,10 +4,10 @@ while test $# -gt 0 ...@@ -4,10 +4,10 @@ while test $# -gt 0
do do
case "$1" in case "$1" in
--debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;; --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;;
-h | --help ) cat <<EOF; exit 0 ;; -h | --help )
Usage: $0 [-h|-n] [configure-options] echo "Usage: $0 [-h|-n] [configure-options]"
--debug Compile with DBUG enabled echo " --debug Compile with DBUG enabled"
EOF exit 0 ;;
*) echo "No such option '$1'" ; exit ;; *) echo "No such option '$1'" ; exit ;;
esac esac
done done
...@@ -15,16 +15,15 @@ done ...@@ -15,16 +15,15 @@ done
gmake -k clean || true gmake -k clean || true
/bin/rm -f */.deps/*.P config.cache /bin/rm -f */.deps/*.P config.cache
aclocal && autoheader && aclocal && automake && autoconf aclocal && autoheader && aclocal && automake && autoconf
(cd bdb/dist && sh s_all) # (cd bdb/dist && sh s_all)
(cd innobase && aclocal && autoheader && aclocal && automake && autoconf) (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 gmake -j 4
cd sql ; mv mysqld mysqld-org ; cd sql ; mv mysqld mysqld-org ;
make CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify gmake CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify
make CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify gmake CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify
make CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov gmake CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov
mv mysqld-org mysqld mv mysqld-org mysqld
...@@ -215,7 +215,7 @@ extern char *strstr(const char *, const char *); ...@@ -215,7 +215,7 @@ extern char *strstr(const char *, const char *);
extern int is_prefix(const char *, const char *); extern int is_prefix(const char *, const char *);
/* Conversion routines */ /* 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); double my_atof(const char *nptr);
extern char *llstr(longlong value,char *buff); extern char *llstr(longlong value,char *buff);
......
...@@ -427,6 +427,9 @@ while test $# -gt 0; do ...@@ -427,6 +427,9 @@ while test $# -gt 0; do
--fast) --fast)
FAST_START=1 FAST_START=1
;; ;;
--use-old-data)
USE_OLD_DATA=1;
;;
-- ) shift; break ;; -- ) shift; break ;;
--* ) $ECHO "Unrecognized option: $1"; exit 1 ;; --* ) $ECHO "Unrecognized option: $1"; exit 1 ;;
* ) break ;; * ) break ;;
...@@ -768,13 +771,15 @@ report_stats () { ...@@ -768,13 +771,15 @@ report_stats () {
mysql_install_db () { mysql_install_db () {
$ECHO "Removing Stale Files" $ECHO "Removing Stale Files"
$RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1" $SLAVE_MYDDIR $MY_LOG_DIR/* if [ -z "$USE_OLD_DATA" ]; then
$RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1"
$ECHO "Installing Master Databases" $ECHO "Installing Master Databases"
$INSTALL_DB $INSTALL_DB
if [ $? != 0 ]; then if [ $? != 0 ]; then
error "Could not install master test DBs" error "Could not install master test DBs"
exit 1 exit 1
fi fi
fi
if [ ! -z "$USE_NDBCLUSTER" ] if [ ! -z "$USE_NDBCLUSTER" ]
then then
$ECHO "Installing Master Databases 1" $ECHO "Installing Master Databases 1"
...@@ -785,6 +790,7 @@ mysql_install_db () { ...@@ -785,6 +790,7 @@ mysql_install_db () {
fi fi
fi fi
$ECHO "Installing Slave Databases" $ECHO "Installing Slave Databases"
$RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/*
$INSTALL_DB -slave $INSTALL_DB -slave
if [ $? != 0 ]; then if [ $? != 0 ]; then
error "Could not install slave test DBs" error "Could not install slave test DBs"
......
...@@ -768,7 +768,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308); ...@@ -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 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308');
INSERT INTO t1 (col1) VALUES (-2.2E-330); INSERT INTO t1 (col1) VALUES (-2.2E-330);
INSERT INTO t1 (col1) VALUES (+1.7E+309); 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); INSERT INTO t1 (col2) VALUES (-1.1E-3);
ERROR 22003: Out of range value adjusted for column 'col2' at row 1 ERROR 22003: Out of range value adjusted for column 'col2' at row 1
INSERT INTO t1 (col1) VALUES ('+1.8E+309'); INSERT INTO t1 (col1) VALUES ('+1.8E+309');
......
drop table if exists t1; drop table if exists t1,t2;
SELECT 10,10.0,10.,.1e+2,100.0e-1; SELECT 10,10.0,10.,.1e+2,100.0e-1;
10 10.0 10. .1e+2 100.0e-1 10 10.0 10. .1e+2 100.0e-1
10 10.0 10 10 10 10 10.0 10 10 10
...@@ -8,6 +8,9 @@ SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; ...@@ -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; 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 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 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)); create table t1 (f1 float(24),f2 float(52));
show full columns from t1; show full columns from t1;
Field Type Collation Null Key Default Extra Privileges Comment Field Type Collation Null Key Default Extra Privileges Comment
......
...@@ -531,7 +531,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308); ...@@ -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'); INSERT INTO t1 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308');
# We don't give warnings for underflow # We don't give warnings for underflow
INSERT INTO t1 (col1) VALUES (-2.2E-330); INSERT INTO t1 (col1) VALUES (-2.2E-330);
--error 1367 --error 1367,1264
INSERT INTO t1 (col1) VALUES (+1.7E+309); INSERT INTO t1 (col1) VALUES (+1.7E+309);
--error 1264 --error 1264
INSERT INTO t1 (col2) VALUES (-1.1E-3); INSERT INTO t1 (col2) VALUES (-1.1E-3);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# Numeric floating point. # Numeric floating point.
--disable_warnings --disable_warnings
drop table if exists t1; drop table if exists t1,t2;
--enable_warnings --enable_warnings
--replace_result e-0 e- e+0 e+ --replace_result e-0 e- e+0 e+
...@@ -11,6 +11,7 @@ SELECT 10,10.0,10.,.1e+2,100.0e-1; ...@@ -11,6 +11,7 @@ SELECT 10,10.0,10.,.1e+2,100.0e-1;
--replace_result e-00 e-0 --replace_result e-00 e-0
SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; 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 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)); create table t1 (f1 float(24),f2 float(52));
show full columns from t1; show full columns from t1;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
also info->read_pos is set to info->read_end. also info->read_pos is set to info->read_end.
If called through open_cached_file(), then the temporary file will 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 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 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 reading and another for writing. Reads are first done from disk and
...@@ -43,7 +43,7 @@ TODO: ...@@ -43,7 +43,7 @@ TODO:
each time the write buffer gets full and it's written to disk, we will 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 always do a disk read to read a part of the buffer from disk to the
read buffer. 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 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. 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, ...@@ -339,7 +339,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
if (info->type == WRITE_CACHE && type == READ_CACHE) if (info->type == WRITE_CACHE && type == READ_CACHE)
info->end_of_file=my_b_tell(info); info->end_of_file=my_b_tell(info);
/* flush cache if we want to reuse it */ /* 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); DBUG_RETURN(1);
info->pos_in_file=seek_offset; info->pos_in_file=seek_offset;
/* Better to do always do a seek */ /* Better to do always do a seek */
...@@ -948,7 +948,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) ...@@ -948,7 +948,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer+=rest_length; Buffer+=rest_length;
Count-=rest_length; Count-=rest_length;
info->write_pos+=rest_length; info->write_pos+=rest_length;
if (flush_io_cache(info)) if (my_b_flush_io_cache(info,1))
return 1; return 1;
if (Count >= IO_SIZE) if (Count >= IO_SIZE)
{ /* Fill first intern buffer */ { /* Fill first intern buffer */
...@@ -1191,6 +1191,7 @@ int end_io_cache(IO_CACHE *info) ...@@ -1191,6 +1191,7 @@ int end_io_cache(IO_CACHE *info)
int error=0; int error=0;
IO_CACHE_CALLBACK pre_close; IO_CACHE_CALLBACK pre_close;
DBUG_ENTER("end_io_cache"); DBUG_ENTER("end_io_cache");
DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info));
#ifdef THREAD #ifdef THREAD
/* /*
...@@ -1200,7 +1201,7 @@ int end_io_cache(IO_CACHE *info) ...@@ -1200,7 +1201,7 @@ int end_io_cache(IO_CACHE *info)
*/ */
if (info->share) if (info->share)
{ {
pthread_cond_destroy (&info->share->cond); pthread_cond_destroy(&info->share->cond);
pthread_mutex_destroy(&info->share->mutex); pthread_mutex_destroy(&info->share->mutex);
info->share=0; info->share=0;
} }
...@@ -1215,7 +1216,7 @@ int end_io_cache(IO_CACHE *info) ...@@ -1215,7 +1216,7 @@ int end_io_cache(IO_CACHE *info)
{ {
info->alloced_buffer=0; info->alloced_buffer=0;
if (info->file != -1) /* File doesn't exist */ 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)); my_free((gptr) info->buffer,MYF(MY_WME));
info->buffer=info->read_pos=(byte*) 0; info->buffer=info->read_pos=(byte*) 0;
} }
......
...@@ -523,8 +523,10 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) ...@@ -523,8 +523,10 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type)
data->prev=lock->write_wait.last; data->prev=lock->write_wait.last;
lock->write_wait.last= &data->next; lock->write_wait.last= &data->next;
data->cond=get_cond(); 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); statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end; goto end;
} }
......
...@@ -1035,7 +1035,9 @@ int Field_decimal::store(longlong nr) ...@@ -1035,7 +1035,9 @@ int Field_decimal::store(longlong nr)
double Field_decimal::val_real(void) double Field_decimal::val_real(void)
{ {
int not_used; 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) longlong Field_decimal::val_int(void)
...@@ -4425,16 +4427,18 @@ int Field_string::store(longlong nr) ...@@ -4425,16 +4427,18 @@ int Field_string::store(longlong nr)
double Field_string::val_real(void) double Field_string::val_real(void)
{ {
int not_used; int not_used;
CHARSET_INFO *cs=charset(); char *end_not_used;
return my_strntod(cs,ptr,field_length,(char**)0,&not_used); CHARSET_INFO *cs= charset();
return my_strntod(cs,ptr,field_length,&end_not_used,&not_used);
} }
longlong Field_string::val_int(void) longlong Field_string::val_int(void)
{ {
int not_used; int not_used;
char *end_not_used;
CHARSET_INFO *cs=charset(); 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) ...@@ -4734,8 +4738,9 @@ int Field_varstring::store(longlong nr)
double Field_varstring::val_real(void) double Field_varstring::val_real(void)
{ {
int not_used; int not_used;
char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); 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); &not_used);
} }
...@@ -4743,9 +4748,10 @@ double Field_varstring::val_real(void) ...@@ -4743,9 +4748,10 @@ double Field_varstring::val_real(void)
longlong Field_varstring::val_int(void) longlong Field_varstring::val_int(void)
{ {
int not_used; int not_used;
char *end_not_used;
uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr);
return my_strntoll(field_charset, ptr+length_bytes, length, 10, NULL, return my_strntoll(field_charset, ptr+length_bytes, length, 10,
&not_used); &end_not_used, &not_used);
} }
...@@ -5339,12 +5345,15 @@ int Field_blob::store(longlong nr) ...@@ -5339,12 +5345,15 @@ int Field_blob::store(longlong nr)
double Field_blob::val_real(void) double Field_blob::val_real(void)
{ {
int not_used; int not_used;
char *blob; char *end_not_used, *blob;
uint32 length;
CHARSET_INFO *cs;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob) if (!blob)
return 0.0; return 0.0;
uint32 length=get_length(ptr); length= get_length(ptr);
CHARSET_INFO *cs=charset(); cs= charset();
return my_strntod(cs,blob,length,(char**)0, &not_used); return my_strntod(cs,blob,length,(char**)0, &not_used);
} }
......
...@@ -844,6 +844,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer, ...@@ -844,6 +844,7 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer,
if (flush_io_cache(to_file)) if (flush_io_cache(to_file))
break; /* purecov: inspected */ break; /* purecov: inspected */
temp=from_file; from_file=to_file; to_file=temp; temp=from_file; from_file=to_file; to_file=temp;
*maxbuffer= (uint) (lastbuff-buffpek)-1; *maxbuffer= (uint) (lastbuff-buffpek)-1;
} }
close_cached_file(to_file); // This holds old result close_cached_file(to_file); // This holds old result
......
...@@ -1292,8 +1292,9 @@ double Item_param::val_real() ...@@ -1292,8 +1292,9 @@ double Item_param::val_real()
case LONG_DATA_VALUE: case LONG_DATA_VALUE:
{ {
int dummy_err; int dummy_err;
char *end_not_used;
return my_strntod(str_value.charset(), (char*) str_value.ptr(), 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: case TIME_VALUE:
/* /*
...@@ -2545,8 +2546,9 @@ Item_num *Item_uint::neg() ...@@ -2545,8 +2546,9 @@ Item_num *Item_uint::neg()
Item_real::Item_real(const char *str_arg, uint length) Item_real::Item_real(const char *str_arg, uint length)
{ {
int error; int error;
char *end; char *end_not_used;
value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end, &error); value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used,
&error);
if (error) if (error)
{ {
/* /*
...@@ -3522,12 +3524,12 @@ void Item_cache_str::store(Item *item) ...@@ -3522,12 +3524,12 @@ void Item_cache_str::store(Item *item)
double Item_cache_str::val_real() double Item_cache_str::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
int err; int err_not_used;
char *end_not_used;
if (value) if (value)
return my_strntod(value->charset(), (char*) value->ptr(), return my_strntod(value->charset(), (char*) value->ptr(),
value->length(), (char**) 0, &err); value->length(), &end_not_used, &err_not_used);
else return (double) 0;
return (double)0;
} }
......
...@@ -58,17 +58,19 @@ uint nr_of_decimals(const char *str) ...@@ -58,17 +58,19 @@ uint nr_of_decimals(const char *str)
return 0; return 0;
} }
double Item_str_func::val_real() double Item_str_func::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
int err; int err_not_used;
char buff[64]; char *end_not_used, buff[64];
String *res, tmp(buff,sizeof(buff), &my_charset_bin); String *res, tmp(buff,sizeof(buff), &my_charset_bin);
res= val_str(&tmp); res= val_str(&tmp);
return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
NULL, &err) : 0.0; &end_not_used, &err_not_used) : 0.0;
} }
longlong Item_str_func::val_int() longlong Item_str_func::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
......
...@@ -591,14 +591,17 @@ void Item_sum_hybrid::clear() ...@@ -591,14 +591,17 @@ void Item_sum_hybrid::clear()
double Item_sum_hybrid::val_real() double Item_sum_hybrid::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
int err;
if (null_value) if (null_value)
return 0.0; return 0.0;
switch (hybrid_type) { switch (hybrid_type) {
case STRING_RESULT: case STRING_RESULT:
{
char *end_not_used;
int err_not_used;
String *res; res=val_str(&str_value); String *res; res=val_str(&str_value);
return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
(char**) 0, &err) : 0.0); &end_not_used, &err_not_used) : 0.0);
}
case INT_RESULT: case INT_RESULT:
if (unsigned_flag) if (unsigned_flag)
return ulonglong2double(sum_int); return ulonglong2double(sum_int);
......
...@@ -244,7 +244,9 @@ static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)), ...@@ -244,7 +244,9 @@ static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)),
static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)), static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)),
const uchar *a, uint a_length, const uchar *a, uint a_length,
const uchar *b, uint b_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 *a_end= a + a_length;
const uchar *b_end= b + b_length; const uchar *b_end= b + b_length;
......
...@@ -750,31 +750,10 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), ...@@ -750,31 +750,10 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)),
char *str, uint length, char *str, uint length,
char **end, int *err) 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) if (length == INT_MAX32)
#else length= 65535; /* Should be big enough */
if (length == INT_MAX32 || str[length] == 0) *end= str + length;
#endif return my_strtod(str, end, err);
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;
} }
......
...@@ -925,6 +925,7 @@ bs: ...@@ -925,6 +925,7 @@ bs:
return (negative ? -((longlong) res) : (longlong) res); return (negative ? -((longlong) res) : (longlong) res);
} }
double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
char *nptr, uint length, char *nptr, uint length,
char **endptr, int *err) char **endptr, int *err)
...@@ -933,7 +934,7 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), ...@@ -933,7 +934,7 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
double res; double res;
register char *b=buf; register char *b=buf;
register const uchar *s= (const uchar*) nptr; register const uchar *s= (const uchar*) nptr;
register const uchar *end; const uchar *end;
my_wc_t wc; my_wc_t wc;
int cnv; int cnv;
...@@ -950,13 +951,10 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), ...@@ -950,13 +951,10 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
break; /* Can't be part of double */ break; /* Can't be part of double */
*b++= (char) wc; *b++= (char) wc;
} }
*b= 0;
errno= 0; *endptr= b;
res=my_strtod(buf, endptr); res= my_strtod(buf, endptr, err);
*err= errno; *endptr= nptr + (uint) (*endptr- buf);
if (endptr)
*endptr=(char*) (*endptr-buf+nptr);
return res; return res;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
An alternative implementation of "strtod()" that is both An alternative implementation of "strtod()" that is both
simplier, and thread-safe. 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 SQL:2003 specifies a number as
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "my_base.h" /* Includes errno.h */ #include "my_base.h" /* Includes errno.h */
#include "m_ctype.h" #include "m_ctype.h"
#define MAX_DBL_EXP 308
#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232
static double scaler10[] = { static double scaler10[] = {
1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90
}; };
...@@ -37,89 +39,154 @@ static double scaler1[] = { ...@@ -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; double result= 0.0;
int negative, ndigits; uint negative= 0, ndigits, dec_digits= 0, pre_zero, neg_exp= 0;
const char *old_str; int exp= 0;
const char *old_str, *end= *end_ptr, *start_of_number;
char next_char;
my_bool overflow=0; my_bool overflow=0;
*error= 0;
if (str >= end)
goto done;
while (my_isspace(&my_charset_latin1, *str)) while (my_isspace(&my_charset_latin1, *str))
str++; {
if (++str == end)
goto done;
}
start_of_number= str;
if ((negative= (*str == '-')) || *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; old_str= str;
while (my_isdigit (&my_charset_latin1, *str)) while ((next_char= *str) >= '0' && next_char <= '9')
{ {
result= result*10.0 + (*str - '0'); result= result*10.0 + (next_char - '0');
str++; 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; double p10= 10;
str++; old_str= ++str;
old_str= str; while (my_isdigit(&my_charset_latin1, (next_char= *str)))
while (my_isdigit (&my_charset_latin1, *str))
{ {
result+= (*str++ - '0')/p10; result+= (next_char - '0')/p10;
p10*=10; if (!result)
pre_zero++;
else
p10*= 10;
if (++str == end)
{
next_char= 0;
break;
} }
ndigits+= str-old_str;
if (!ndigits) str--;
} }
if (ndigits && (*str=='e' || *str=='E')) /* 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 ((next_char == 'e' || next_char == 'E') &&
dec_digits + ndigits != 0 && str < end-1)
{ {
int exp= 0;
int neg= 0;
const char *old_str= str++; const char *old_str= str++;
if ((neg= (*str == '-')) || *str == '+') if ((neg_exp= (*str == '-')) || *str == '+')
str++; str++;
if (!my_isdigit (&my_charset_latin1, *str)) if (str == end || !my_isdigit(&my_charset_latin1, *str))
str= old_str; str= old_str;
else else
{ {
double scaler= 1.0; do
while (my_isdigit (&my_charset_latin1, *str))
{ {
if (exp < 9999) /* protection against exp overflow */ if (exp < 9999) /* protec against exp overfl. */
exp= exp*10 + *str - '0'; exp= exp*10 + *str - '0';
str++; str++;
} while (str < end && my_isdigit(&my_charset_latin1, *str));
} }
if (exp >= 1000) }
if ((exp= neg_exp ? exp + pre_zero : exp - pre_zero))
{
double scaler;
if (exp < 0)
{ {
if (neg) 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_exp)
result= 0.0; result= 0.0;
else else
overflow= 1; overflow= 1;
goto done; goto done;
} }
}
scaler= 1.0;
while (exp >= 100) while (exp >= 100)
{ {
scaler*= 1.0e100; scaler*= 1.0e100;
exp-= 100; exp-= 100;
} }
scaler*= scaler10[exp/10]*scaler1[exp%10]; scaler*= scaler10[exp/10]*scaler1[exp%10];
if (neg) if (neg_exp)
result/= scaler; result/= scaler;
else else
result*= scaler; result*= scaler;
} }
}
done: done:
if (end) *end_ptr= (char*) str; /* end of number */
*end = (char *)str;
if (overflow || isinf(result)) if (overflow || isinf(result))
{ {
result= DBL_MAX; result= DBL_MAX;
errno= EOVERFLOW; *error= EOVERFLOW;
} }
return negative ? -result : result; return negative ? -result : result;
...@@ -127,6 +194,7 @@ done: ...@@ -127,6 +194,7 @@ done:
double my_atof(const char *nptr) 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));
} }
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