mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Changed interface for my_strntod() to make it more general and more portable
This commit is contained in:
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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');
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
29
sql/field.cc
29
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, ¬_used);
|
||||
char *end_not_used;
|
||||
return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used,
|
||||
¬_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,¬_used);
|
||||
char *end_not_used;
|
||||
CHARSET_INFO *cs= charset();
|
||||
return my_strntod(cs,ptr,field_length,&end_not_used,¬_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,¬_used);
|
||||
return my_strntoll(cs,ptr,field_length,10,&end_not_used,¬_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,
|
||||
¬_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,
|
||||
¬_used);
|
||||
return my_strntoll(field_charset, ptr+length_bytes, length, 10,
|
||||
&end_not_used, ¬_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, ¬_used);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
24
sql/item.cc
24
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
170
strings/strtod.c
170
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;
|
||||
|
||||
while (my_isspace(&my_charset_latin1, *str))
|
||||
str++;
|
||||
*error= 0;
|
||||
if (str >= end)
|
||||
goto done;
|
||||
|
||||
while (my_isspace(&my_charset_latin1, *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++;
|
||||
}
|
||||
ndigits= str-old_str;
|
||||
|
||||
if (*str == '.')
|
||||
{
|
||||
double p10=10;
|
||||
str++;
|
||||
old_str= str;
|
||||
while (my_isdigit (&my_charset_latin1, *str))
|
||||
result= result*10.0 + (next_char - '0');
|
||||
if (++str == end)
|
||||
{
|
||||
result+= (*str++ - '0')/p10;
|
||||
p10*=10;
|
||||
next_char= 0; /* Found end of string */
|
||||
break;
|
||||
}
|
||||
ndigits+= str-old_str;
|
||||
if (!ndigits) str--;
|
||||
start_of_number= 0; /* Found digit */
|
||||
}
|
||||
if (ndigits && (*str=='e' || *str=='E'))
|
||||
ndigits= (uint) (str-old_str);
|
||||
|
||||
pre_zero= 0;
|
||||
if (next_char == '.' && str < end-1)
|
||||
{
|
||||
double p10= 10;
|
||||
old_str= ++str;
|
||||
while (my_isdigit(&my_charset_latin1, (next_char= *str)))
|
||||
{
|
||||
result+= (next_char - '0')/p10;
|
||||
if (!result)
|
||||
pre_zero++;
|
||||
else
|
||||
p10*= 10;
|
||||
if (++str == end)
|
||||
{
|
||||
next_char= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 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++;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user