summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2005-01-15 12:28:38 +0200
committerunknown <monty@mysql.com>2005-01-15 12:28:38 +0200
commit5437a90dfafacee48603f8977d2018796c35f526 (patch)
treee3a0da70f844473e00b8fb81958bb7d0607dc880 /strings
parent7222ac501454363f7d3df59ab7feac50265336f7 (diff)
downloadmariadb-git-5437a90dfafacee48603f8977d2018796c35f526.tar.gz
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.
Diffstat (limited to 'strings')
-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
4 files changed, 130 insertions, 83 deletions
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));
}
-