summaryrefslogtreecommitdiff
path: root/strings
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2005-02-19 19:00:41 +0200
committerunknown <monty@mysql.com>2005-02-19 19:00:41 +0200
commit6c8ae9d65ec0fe3ee9c8349dd7f8cc7336c958dd (patch)
tree5a44a1612b30cc4765614c35e5172d824e16bb09 /strings
parent0bc02450a61180a5827ce4ab2a2b3538c1c1ce91 (diff)
parent64cc538bda5908e2688a1ba08a9ff156971a102b (diff)
downloadmariadb-git-6c8ae9d65ec0fe3ee9c8349dd7f8cc7336c958dd.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/my/mysql-5.0 BUILD/SETUP.sh: Auto merged mysql-test/r/ps_6bdb.result: Auto merged sql/item.h: Auto merged sql/item_func.cc: Auto merged sql/item_func.h: Auto merged sql/log_event.cc: Auto merged sql/my_decimal.cc: Auto merged sql/my_decimal.h: Auto merged sql/mysql_priv.h: Auto merged sql/sp_head.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_select.cc: Auto merged
Diffstat (limited to 'strings')
-rw-r--r--strings/decimal.c233
1 files changed, 137 insertions, 96 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 16c80158722..212bd7204f6 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -743,12 +743,12 @@ int decimal_shift(decimal *dec, int shift)
Convert string to decimal
SYNOPSIS
- str2decl()
- from - value to convert
+ internal_str2decl()
+ from - value to convert. Doesn't have to be \0 terminated!
to - decimal where where the result will be stored
to->buf and to->len must be set.
- end - if not NULL, *end will be set to the char where
- conversion ended
+ end - Pointer to pointer to end of string. Will on return be
+ set to the char after the last used character
fixed - use to->intg, to->frac as limits for input number
NOTE
@@ -757,31 +757,36 @@ int decimal_shift(decimal *dec, int shift)
RETURN VALUE
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM
+ In case of E_DEC_FATAL_ERROR *to is set to decimal zero
+ (to make error handling easier)
*/
-static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
+int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed)
{
- char *s=from, *s1, *endp;
+ const char *s= from, *s1, *endp, *end_of_string= *end;
int i, intg, frac, error, intg1, frac1;
dec1 x,*buf;
- LINT_INIT(error);
sanity(to);
- while (my_isspace(&my_charset_latin1, *s))
+ error= E_DEC_BAD_NUM; /* In case of bad number */
+ while (s < end_of_string && my_isspace(&my_charset_latin1, *s))
s++;
+ if (s == end_of_string)
+ goto fatal_error;
+
if ((to->sign= (*s == '-')))
s++;
else if (*s == '+')
s++;
s1=s;
- while (my_isdigit(&my_charset_latin1, *s))
+ while (s < end_of_string && my_isdigit(&my_charset_latin1, *s))
s++;
intg=s-s1;
- if (*s=='.')
+ if (s < end_of_string && *s=='.')
{
endp= s+1;
- while (my_isdigit(&my_charset_latin1, *endp))
+ while (s < end_of_string && my_isdigit(&my_charset_latin1, *endp))
endp++;
frac= endp - s - 1;
}
@@ -791,12 +796,12 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
endp= s;
}
- if (end)
- *end= endp;
+ *end= (char*) endp;
if (frac+intg == 0)
- return E_DEC_BAD_NUM;
+ goto fatal_error;
+ error= 0;
if (fixed)
{
if (frac > to->frac)
@@ -812,7 +817,10 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
intg1=ROUND_UP(intg);
frac1=ROUND_UP(frac);
if (intg1+frac1 > to->len)
- return E_DEC_OOM;
+ {
+ error= E_DEC_OOM;
+ goto fatal_error;
+ }
}
else
{
@@ -861,36 +869,43 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
}
if (i)
*buf=x*powers10[DIG_PER_DEC1-i];
- if (*endp == 'e' || *endp == 'E')
- {
- long exp= strtol(endp + 1, &endp, 10);
-
- if (end)
- *end= endp;
- if (exp > INT_MAX/2)
- return E_DEC_OVERFLOW;
- if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW)
- return E_DEC_TRUNCATED;
+ /* Handle exponent */
+ if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E'))
+ {
+ int str_error;
+ longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error);
- if(error != E_DEC_OVERFLOW)
- error= decimal_shift(to, exp);
+ if (end_of_string != endp +1) /* If at least one digit */
+ {
+ *end= (char*) end_of_string;
+ if (str_error > 0)
+ {
+ error= E_DEC_BAD_NUM;
+ goto fatal_error;
+ }
+ if (exp > INT_MAX/2 || (str_error == 0 && exp < 0))
+ {
+ error= E_DEC_OVERFLOW;
+ goto fatal_error;
+ }
+ if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW)
+ {
+ error= E_DEC_TRUNCATED;
+ goto fatal_error;
+ }
+ if (error != E_DEC_OVERFLOW)
+ error= decimal_shift(to, (int) exp);
+ }
}
+ return error;
+fatal_error:
+ decimal_make_zero(to);
return error;
}
-int string2decimal(char *from, decimal *to, char **end)
-{
- return str2dec(from, to, end, 0);
-}
-
-int string2decimal_fixed(char *from, decimal *to, char **end)
-{
- return str2dec(from, to, end, 1);
-}
-
/*
Convert decimal to double
@@ -932,9 +947,10 @@ int decimal2double(decimal *from, double *to)
int double2decimal(double from, decimal *to)
{
/* TODO: fix it, when we'll have dtoa */
- char s[400];
+ char s[400], *end;
sprintf(s, "%f", from);
- return string2decimal(s, to, 0);
+ end= strend(s);
+ return string2decimal(s, to, &end);
}
static int ull2dec(ulonglong from, decimal *to)
@@ -2160,13 +2176,13 @@ void check_result_code(int actual, int want)
{
if (actual != want)
{
- printf("\n^^^^^^^^^^^^^ mast return %d\n", want);
+ printf("\n^^^^^^^^^^^^^ must return %d\n", want);
exit(1);
}
}
-void print_decimal(decimal *d, char *orig, int actual, int want)
+void print_decimal(decimal *d, const char *orig, int actual, int want)
{
char s[100];
int slen=sizeof(s);
@@ -2218,38 +2234,41 @@ void test_d2s()
dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen);
}
-void test_s2d(char *s, char *orig, int ex)
+void test_s2d(const char *s, const char *orig, int ex)
{
- char s1[100];
+ char s1[100], *end;
int res;
sprintf(s1, "'%s'", s);
+ end= strend(s);
printf("len=%2d %-30s => res=%d ", a.len, s1,
- (res= string2decimal(s, &a, 0)));
+ (res= string2decimal(s, &a, &end)));
print_decimal(&a, orig, res, ex);
printf("\n");
}
-void test_d2f(char *s, int ex)
+void test_d2f(const char *s, int ex)
{
- char s1[100];
+ char s1[100], *end;
double x;
int res;
sprintf(s1, "'%s'", s);
- string2decimal(s, &a, 0);
+ end= strend(s);
+ string2decimal(s, &a, &end);
res=decimal2double(&a, &x);
if (full) dump_decimal(&a);
printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x);
check_result_code(res, ex);
}
-void test_d2b2d(char *str, int p, int s, char *orig, int ex)
+void test_d2b2d(const char *str, int p, int s, const char *orig, int ex)
{
- char s1[100], buf[100];
+ char s1[100], buf[100], *end;
int res, i, size=decimal_bin_size(p, s);
sprintf(s1, "'%s'", str);
- string2decimal(str, &a, 0);
+ end= strend(str);
+ string2decimal(str, &a, &end);
res=decimal2bin(&a, buf, p, s);
printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size);
if (full)
@@ -2263,6 +2282,7 @@ void test_d2b2d(char *str, int p, int s, char *orig, int ex)
print_decimal(&a, orig, res, ex);
printf("\n");
}
+
void test_f2d(double from, int ex)
{
int res;
@@ -2273,7 +2293,7 @@ void test_f2d(double from, int ex)
printf("\n");
}
-void test_ull2d(ulonglong from, char *orig, int ex)
+void test_ull2d(ulonglong from, const char *orig, int ex)
{
char s[100];
int res;
@@ -2285,7 +2305,7 @@ void test_ull2d(ulonglong from, char *orig, int ex)
printf("\n");
}
-void test_ll2d(longlong from, char *orig, int ex)
+void test_ll2d(longlong from, const char *orig, int ex)
{
char s[100];
int res;
@@ -2297,13 +2317,14 @@ void test_ll2d(longlong from, char *orig, int ex)
printf("\n");
}
-void test_d2ull(char *s, char *orig, int ex)
+void test_d2ull(const char *s, const char *orig, int ex)
{
- char s1[100];
+ char s1[100], *end;
ulonglong x;
int res;
- string2decimal(s, &a, 0);
+ end= strend(s);
+ string2decimal(s, &a, &end);
res=decimal2ulonglong(&a, &x);
if (full) dump_decimal(&a);
longlong10_to_str(x,s1,10);
@@ -2316,13 +2337,14 @@ void test_d2ull(char *s, char *orig, int ex)
}
}
-void test_d2ll(char *s, char *orig, int ex)
+void test_d2ll(const char *s, const char *orig, int ex)
{
- char s1[100];
+ char s1[100], *end;
longlong x;
int res;
- string2decimal(s, &a, 0);
+ end= strend(s);
+ string2decimal(s, &a, &end);
res=decimal2longlong(&a, &x);
if (full) dump_decimal(&a);
longlong10_to_str(x,s1,-10);
@@ -2335,39 +2357,45 @@ void test_d2ll(char *s, char *orig, int ex)
}
}
-void test_da(char *s1, char *s2, char *orig, int ex)
+void test_da(const char *s1, const char *s2, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' + '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_add(&a, &b, &c);
printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex);
printf("\n");
}
-void test_ds(char *s1, char *s2, char *orig, int ex)
+void test_ds(const char *s1, const char *s2, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' - '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_sub(&a, &b, &c);
printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex);
printf("\n");
}
-void test_dc(char *s1, char *s2, int orig)
+void test_dc(const char *s1, const char *s2, int orig)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' <=> '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_cmp(&a, &b);
printf("%-40s => res=%d\n", s, res);
if (orig != res)
@@ -2377,26 +2405,30 @@ void test_dc(char *s1, char *s2, int orig)
}
}
-void test_dm(char *s1, char *s2, char *orig, int ex)
+void test_dm(const char *s1, const char *s2, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' * '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_mul(&a, &b, &c);
printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex);
printf("\n");
}
-void test_dv(char *s1, char *s2, char *orig, int ex)
+void test_dv(const char *s1, const char *s2, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' / '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_div(&a, &b, &c, 5);
printf("%-40s => res=%d ", s, res);
check_result_code(res, ex);
@@ -2407,13 +2439,15 @@ void test_dv(char *s1, char *s2, char *orig, int ex)
printf("\n");
}
-void test_md(char *s1, char *s2, char *orig, int ex)
+void test_md(const char *s1, const char *s2, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' %% '%s'", s1, s2);
- string2decimal(s1, &a, 0);
- string2decimal(s2, &b, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
+ end= strend(s2);
+ string2decimal(s2, &b, &end);
res=decimal_mod(&a, &b, &c);
printf("%-40s => res=%d ", s, res);
check_result_code(res, ex);
@@ -2424,14 +2458,17 @@ void test_md(char *s1, char *s2, char *orig, int ex)
printf("\n");
}
-char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"};
+const char *round_mode[]=
+{"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"};
-void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex)
+void test_ro(const char *s1, int n, decimal_round_mode mode, const char *orig,
+ int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
- string2decimal(s1, &a, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
res=decimal_round(&a, &b, n, mode);
printf("%-40s => res=%d ", s, res);
print_decimal(&b, orig, res, ex);
@@ -2439,7 +2476,7 @@ void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex)
}
-void test_mx(int precision, int frac, char *orig)
+void test_mx(int precision, int frac, const char *orig)
{
char s[100];
sprintf(s, "%d, %d", precision, frac);
@@ -2450,15 +2487,17 @@ void test_mx(int precision, int frac, char *orig)
}
-void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex)
+void test_pr(const char *s1, int prec, int dec, char filler, const char *orig,
+ int ex)
{
- char s[100];
+ char s[100], *end;
char s2[100];
int slen= sizeof(s2);
int res;
sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler);
- string2decimal(s1, &a, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
res= decimal2string(&a, s2, &slen, prec, dec, filler);
printf("%-40s => res=%d '%s'", s, res, s2);
check_result_code(res, ex);
@@ -2471,12 +2510,13 @@ void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex)
}
-void test_sh(char *s1, int shift, char *orig, int ex)
+void test_sh(const char *s1, int shift, const char *orig, int ex)
{
- char s[100];
+ char s[100], *end;
int res;
sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift));
- string2decimal(s1, &a, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
res= decimal_shift(&a, shift);
printf("%-40s => res=%d ", s, res);
print_decimal(&a, orig, res, ex);
@@ -2484,12 +2524,13 @@ void test_sh(char *s1, int shift, char *orig, int ex)
}
-void test_fr(char *s1, char *orig)
+void test_fr(const char *s1, const char *orig)
{
- char s[100];
+ char s[100], *end;
sprintf(s, "'%s'", s1);
printf("%-40s => ", s);
- string2decimal(s1, &a, 0);
+ end= strend(s1);
+ string2decimal(s1, &a, &end);
decimal_optimize_fraction(&a);
print_decimal(&a, orig, 0, 0);
printf("\n");