mariadb/strings/my_strtoll10.c
unknown c807724f36 Review of code pushed since last 5.0 pull:
Ensure that ccache is also used for C programs
mysql: Ensure that 'delimiter' works the same way in batch mode as in normal mode
mysqldump: Change to use ;; (instead of //) as a stored procedure/trigger delimiter
Fixed test cases by adding missing DROP's and rename views to be of type 'v#'
Removed MY_UNIX_PATH from fn_format()
Removed current_db_used from TABLE_LIST
Removed usage of 'current_thd' in Item_splocal
Removed some compiler warnings
A bit faster longlong2str code



BUILD/FINISH.sh:
  Ensure that ccache is also used for C programs
BUILD/SETUP.sh:
  Ensure that ccache is also used for C programs
client/mysql.cc:
  More debugging
  Ensure that 'delimiter' works the same way in batch mode as in normal mode.
  Compare 'delimiter' command case-insensitive.
  The above fixes the delimiter bugs so that we can now use ;; as a trigger/SP function delimiter in mysqldump.
client/mysqldump.c:
  Indentation fixes
  Use ;; as a delmimiter for stored procedures and triggers instead of //
client/mysqltest.c:
  Indentation fixes
include/my_sys.h:
  Remove not needed MY_UNIX_PATH parameter
mysql-test/r/alter_table.result:
  Better to reuse mysqltest database (test didn't properly delete mysqltest1 at start)
mysql-test/r/func_str.result:
  More testing of CONV() (to ensure that longlong2str() works correctly)
mysql-test/r/information_schema.result:
  Drop all used tables and views
  Rename view tables to 'v#' to ensure that if this test fails, not a lot of other test fails
mysql-test/r/information_schema_inno.result:
  Drop all used tables
mysql-test/r/multi_statement.result:
  Drop used tables
mysql-test/r/mysql.result:
  Add error messages to result
mysql-test/r/mysqldump.result:
  ;; is now used as SP/trigger delimiter
mysql-test/r/mysqlshow.result:
  Drop used tables
mysql-test/r/temp_table.result:
  Drop used views
  Rename views to v#
mysql-test/t/alter_table.test:
  Better to reuse mysqltest database (test didn't properly delete mysqltest1 at start)
mysql-test/t/func_str.test:
  More testing of CONV() (to ensure that longlong2str() works correctly)
mysql-test/t/information_schema.test:
  Drop all used tables and views
  Rename view tables to 'v#' to ensure that if this test fails, not a lot of other test fails
mysql-test/t/information_schema_inno.test:
  Drop all used tables
mysql-test/t/multi_statement.test:
  Drop used tables
mysql-test/t/mysql.test:
  Add error messages to result
mysql-test/t/mysqlshow.test:
  Drop used tables
mysql-test/t/temp_table.test:
  Drop used views
  Rename views to v#
mysys/mf_format.c:
  Remove not needed MY_UNIX_PATH parameter
  (This goes against how fn_format() is supposed to work and also conflicts with other options like MY_RETURN_REAL_PATH)
sql/ha_federated.cc:
  Removed extra empty line
sql/item.cc:
  Use 'str_value' instead of 'str_value_ptr' to hold result for Item_splocal
  Remove some calls to 'thd' in Item_splocal by making 'thd' a class variable
  One doesn't have to set 'null_value' when calling 'is_null()'
sql/item.h:
  Add THD as a class variable to Item_splocal
  Use 'str_value' instead of 'str_value_ptr' to hold temp result
  Fixed bug in Item_hex when used in CAST()
sql/item_func.cc:
  Optimize new code
sql/log_event.cc:
  Move 'to_unix_path()' out of fn_format()
sql/opt_range.cc:
  Simplify code
sql/sp_head.cc:
  Ensure that Item_splocal has thd set before we call '->this_item()'
sql/sql_class.cc:
  Return error if Statement::insert() fails in either hash_insert()
sql/sql_parse.cc:
  Remove 'current_db_used' as we can trivially check if db table qualifier was used without this.
  Simplify code
sql/sql_prepare.cc:
  Use enum instead of const int, to avoid ugly code for VC++
sql/structs.h:
  Remove compiler warnings when using STRING_WITH_LEN() with constant strings.
sql/table.cc:
  Fixed indentation
sql/table.h:
  Remove not needed current_db_used
strings/decimal.c:
  Simplify code
strings/longlong2str-x86.s:
  A bit faster longlong2str.
  (Took some ideas from Peter Gulutzan's code)
strings/my_strtoll10.c:
  Simplify code for MetroWerks compiler
2005-10-06 17:54:43 +03:00

245 lines
6.5 KiB
C

/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h> /* Needed for MY_ERRNO_ERANGE */
#include <m_string.h>
#undef ULONGLONG_MAX
/* Needed under MetroWerks Compiler, since MetroWerks compiler does not properly handle a constant expression containing a mod operator */
#if defined(__NETWARE__) && defined(__MWERKS__)
static ulonglong ulonglong_max= ~(ulonglong) 0;
#define ULONGLONG_MAX ulonglong_max
#else
#define ULONGLONG_MAX (~(ulonglong) 0)
#endif /* __NETWARE__ && __MWERKS__ */
#define MAX_NEGATIVE_NUMBER ((ulonglong) LL(0x8000000000000000))
#define INIT_CNT 9
#define LFACTOR ULL(1000000000)
#define LFACTOR1 ULL(10000000000)
#define LFACTOR2 ULL(100000000000)
static unsigned long lfactor[9]=
{
1L, 10L, 100L, 1000L, 10000L, 100000L, 1000000L, 10000000L, 100000000L
};
/*
Convert a string to an to unsigned long long integer value
SYNOPSYS
my_strtoll10()
nptr in pointer to the string to be converted
endptr in/out pointer to the end of the string/
pointer to the stop character
error out returned error code
DESCRIPTION
This function takes the decimal representation of integer number
from string nptr and converts it to an signed or unsigned
long long integer value.
Space characters and tab are ignored.
A sign character might precede the digit characters. The number
may have any number of pre-zero digits.
The function stops reading the string nptr at the first character
that is not a decimal digit. If endptr is not NULL then the function
will not read characters after *endptr.
RETURN VALUES
Value of string as a signed/unsigned longlong integer
if no error and endptr != NULL, it will be set to point at the character
after the number
The error parameter contains information how things went:
-1 Number was an ok negative number
0 ok
ERANGE If the the value of the converted number exceeded the
maximum negative/unsigned long long integer.
In this case the return value is ~0 if value was
positive and LONGLONG_MIN if value was negative.
EDOM If the string didn't contain any digits. In this case
the return value is 0.
If endptr is not NULL the function will store the end pointer to
the stop character here.
*/
longlong my_strtoll10(const char *nptr, char **endptr, int *error)
{
const char *s, *end, *start, *n_end, *true_end;
char *dummy;
unsigned char c;
unsigned long i, j, k;
ulonglong li;
int negative;
ulong cutoff, cutoff2, cutoff3;
s= nptr;
/* If fixed length string */
if (endptr)
{
end= *endptr;
while (s != end && (*s == ' ' || *s == '\t'))
s++;
if (s == end)
goto no_conv;
}
else
{
endptr= &dummy; /* Easier end test */
while (*s == ' ' || *s == '\t')
s++;
if (!*s)
goto no_conv;
/* This number must be big to guard against a lot of pre-zeros */
end= s+65535; /* Can't be longer than this */
}
/* Check for a sign. */
negative= 0;
if (*s == '-')
{
*error= -1; /* Mark as negative number */
negative= 1;
if (++s == end)
goto no_conv;
cutoff= MAX_NEGATIVE_NUMBER / LFACTOR2;
cutoff2= (MAX_NEGATIVE_NUMBER % LFACTOR2) / 100;
cutoff3= MAX_NEGATIVE_NUMBER % 100;
}
else
{
*error= 0;
if (*s == '+')
{
if (++s == end)
goto no_conv;
}
cutoff= ULONGLONG_MAX / LFACTOR2;
cutoff2= ULONGLONG_MAX % LFACTOR2 / 100;
cutoff3= ULONGLONG_MAX % 100;
}
/* Handle case where we have a lot of pre-zero */
if (*s == '0')
{
i= 0;
do
{
if (++s == end)
goto end_i; /* Return 0 */
}
while (*s == '0');
n_end= s+ INIT_CNT;
}
else
{
/* Read first digit to check that it's a valid number */
if ((c= (*s-'0')) > 9)
goto no_conv;
i= c;
n_end= ++s+ INIT_CNT-1;
}
/* Handle first 9 digits and store them in i */
if (n_end > end)
n_end= end;
for (; s != n_end ; s++)
{
if ((c= (*s-'0')) > 9)
goto end_i;
i= i*10+c;
}
if (s == end)
goto end_i;
/* Handle next 9 digits and store them in j */
j= 0;
start= s; /* Used to know how much to shift i */
n_end= true_end= s + INIT_CNT;
if (n_end > end)
n_end= end;
do
{
if ((c= (*s-'0')) > 9)
goto end_i_and_j;
j= j*10+c;
} while (++s != n_end);
if (s == end)
{
if (s != true_end)
goto end_i_and_j;
goto end3;
}
if ((c= (*s-'0')) > 9)
goto end3;
/* Handle the next 1 or 2 digits and store them in k */
k=c;
if (++s == end || (c= (*s-'0')) > 9)
goto end4;
k= k*10+c;
*endptr= (char*) ++s;
/* number string should have ended here */
if (s != end && (c= (*s-'0')) <= 9)
goto overflow;
/* Check that we didn't get an overflow with the last digit */
if (i > cutoff || (i == cutoff && ((j > cutoff2 || j == cutoff2) &&
k > cutoff3)))
goto overflow;
li=i*LFACTOR2+ (ulonglong) j*100 + k;
return (longlong) li;
overflow: /* *endptr is set here */
*error= MY_ERRNO_ERANGE;
return negative ? LONGLONG_MIN : (longlong) ULONGLONG_MAX;
end_i:
*endptr= (char*) s;
return (negative ? ((longlong) -(long) i) : (longlong) i);
end_i_and_j:
li= (ulonglong) i * lfactor[(uint) (s-start)] + j;
*endptr= (char*) s;
return (negative ? -((longlong) li) : (longlong) li);
end3:
li=(ulonglong) i*LFACTOR+ (ulonglong) j;
*endptr= (char*) s;
return (negative ? -((longlong) li) : (longlong) li);
end4:
li=(ulonglong) i*LFACTOR1+ (ulonglong) j * 10 + k;
*endptr= (char*) s;
if (negative)
{
if (li > MAX_NEGATIVE_NUMBER)
goto overflow;
return -((longlong) li);
}
return (longlong) li;
no_conv:
/* There was no number to convert. */
*error= MY_ERRNO_EDOM;
*endptr= (char *) nptr;
return 0;
}