Commit a37e91e4 authored by monty@mysql.com's avatar monty@mysql.com

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

parent b8dc0c5d
......@@ -4,10 +4,10 @@ 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
-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
......@@ -15,16 +15,15 @@ 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,13 +771,15 @@ report_stats () {
mysql_install_db () {
$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"
$INSTALL_DB
if [ $? != 0 ]; then
error "Could not install master test DBs"
exit 1
fi
fi
if [ ! -z "$USE_NDBCLUSTER" ]
then
$ECHO "Installing Master Databases 1"
......@@ -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');
......
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;
}
......
......@@ -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);
}
......
......@@ -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
......
......@@ -1292,8 +1292,9 @@ double Item_param::val_real()
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:
/*
......@@ -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);
......
......@@ -244,7 +244,9 @@ 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 *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,6 +925,7 @@ bs:
return (negative ? -((longlong) res) : (longlong) res);
}
double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
char *nptr, uint length,
char **endptr, int *err)
......@@ -933,7 +934,7 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
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;
}
......
......@@ -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 (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++;
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++;
} 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;
else
overflow= 1;
goto done;
}
}
scaler= 1.0;
while (exp >= 100)
{
scaler*= 1.0e100;
exp-= 100;
}
scaler*= scaler10[exp/10]*scaler1[exp%10];
if (neg)
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));
}
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