diff options
author | unknown <monty@mysql.com> | 2005-02-19 19:00:41 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-02-19 19:00:41 +0200 |
commit | 6c8ae9d65ec0fe3ee9c8349dd7f8cc7336c958dd (patch) | |
tree | 5a44a1612b30cc4765614c35e5172d824e16bb09 /strings | |
parent | 0bc02450a61180a5827ce4ab2a2b3538c1c1ce91 (diff) | |
parent | 64cc538bda5908e2688a1ba08a9ff156971a102b (diff) | |
download | mariadb-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.c | 233 |
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"); |