diff options
author | unknown <monty@mysql.com> | 2005-04-29 17:03:34 +0300 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-04-29 17:03:34 +0300 |
commit | 97b0821462cd21d5051b3264f072ea3d4a7a8d7f (patch) | |
tree | 0caae1ad50324015508cbda7e4ef72f92ca69c25 | |
parent | 2a69f0049b3fd6e765e2f58a81ea7b5e3d5dcd1c (diff) | |
download | mariadb-git-97b0821462cd21d5051b3264f072ea3d4a7a8d7f.tar.gz |
CAST(string_argument AS UNSIGNED) didn't work for big integers above the signed range. (Bug #7036)
Produce warnings of wrong cast of strings to signed/unsigned.
Don't block not resolved IP's if DNS server is down (Bug #8467)
Fix compiler problems with MinGW (Bug #8872)
configure.in:
Fix compiler problems with MinGW (Bug #8872)
include/config-win.h:
Fix compiler problems with MinGW (Bug #8872)
include/my_global.h:
Fix compiler problems with MinGW (Bug #8872)
mysql-test/r/cast.result:
Test for cast to signed/unsigned outside of range (Bug #7036)
mysql-test/t/cast.test:
Test for cast to signed/unsigned outside of range (Bug #7036)
mysys/default.c:
Cleanup (combine identical code).
Done mainly by Jani
sql/field.h:
Added cast_to_int_type() to ensure that enums are casted as numbers
sql/hostname.cc:
Don't block not resolved IP's if DNS server is down (Bug #8467)
sql/item.h:
Added cast_to_int_type() to ensure that enums are casted as numbers
sql/item_func.cc:
CAST(string_argument AS UNSIGNED) didn't work for big integers above the
signed range. (Bug #7036)
Produce warnings of wrong cast of strings to signed/unsigned
sql/item_func.h:
CAST(string_argument AS UNSIGNED) didn't work for big integers above the
signed range. (Bug #7036)
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | include/config-win.h | 17 | ||||
-rw-r--r-- | include/my_global.h | 2 | ||||
-rw-r--r-- | mysql-test/r/cast.result | 71 | ||||
-rw-r--r-- | mysql-test/t/cast.test | 26 | ||||
-rw-r--r-- | mysys/default.c | 103 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/hostname.cc | 9 | ||||
-rw-r--r-- | sql/item.h | 7 | ||||
-rw-r--r-- | sql/item_func.cc | 73 | ||||
-rw-r--r-- | sql/item_func.h | 9 |
11 files changed, 263 insertions, 59 deletions
diff --git a/configure.in b/configure.in index e90bea90dad..6efdc56d450 100644 --- a/configure.in +++ b/configure.in @@ -1860,6 +1860,9 @@ If you are using gcc 2.8.# you should upgrade to egcs 1.0.3 or newer and try again]); fi fi +AC_CHECK_TYPES([sigset_t, off_t], [], [], [#include <sys/types.h>]) +AC_CHECK_TYPES([size_t], [], [], [#include <stdio.h>]) + MYSQL_PTHREAD_YIELD ###################################################################### diff --git a/include/config-win.h b/include/config-win.h index 472190e53ca..b3865c1fda7 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -106,20 +106,33 @@ functions */ /* Type information */ +#if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned short ushort; typedef unsigned int uint; +#endif /* defined(__EMX__) || !defined(HAVE_UINT) */ + typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */ typedef __int64 longlong; +#ifndef HAVE_SIGSET_T typedef int sigset_t; +#endif #define longlong_defined -/* off_t should not be __int64 because of conflicts in header files; - Use my_off_t or os_off_t instead */ +/* + off_t should not be __int64 because of conflicts in header files; + Use my_off_t or os_off_t instead +*/ +#ifndef HAVE_OFF_T typedef long off_t; +#endif typedef __int64 os_off_t; #ifdef _WIN64 typedef UINT_PTR rf_SetTimer; #else +#ifndef HAVE_SIZE_T typedef unsigned int size_t; +#endif typedef uint rf_SetTimer; #endif diff --git a/include/my_global.h b/include/my_global.h index 745179e8a06..bf6f3b52c4b 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -393,6 +393,8 @@ int __void__; #endif #if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned int uint; typedef unsigned short ushort; #endif diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 636e2603f9b..7cd0934f7a3 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -4,9 +4,6 @@ CAST(1-2 AS UNSIGNED) select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) -1 -select CONVERT('-1',UNSIGNED); -CONVERT('-1',UNSIGNED) -18446744073709551615 select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1 18446744073709551611 18446744073709551611 @@ -57,6 +54,41 @@ CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)) select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) 2004 +select cast('18446744073709551616' as unsigned); +cast('18446744073709551616' as unsigned) +18446744073709551615 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('18446744073709551616' as signed); +cast('18446744073709551616' as signed) +-1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('9223372036854775809' as signed); +cast('9223372036854775809' as signed) +-9223372036854775807 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('-1' as unsigned); +cast('-1' as unsigned) +18446744073709551615 +Warnings: +Warning 1105 Cast to unsigned converted negative integer to it's positive complement +select cast('abc' as signed); +cast('abc' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'abc' +select cast('1a' as signed); +cast('1a' as signed) +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1a' +select cast('' as signed); +cast('' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' set names binary; select cast(_latin1'test' as char character set latin2); cast(_latin1'test' as char character set latin2) @@ -187,3 +219,36 @@ timediff(cast('2004-12-30 12:00:00' as time), '12:00:00') select timediff(cast('1 12:00:00' as time), '12:00:00'); timediff(cast('1 12:00:00' as time), '12:00:00') 24:00:00 +select cast(18446744073709551615 as unsigned); +cast(18446744073709551615 as unsigned) +18446744073709551615 +select cast(18446744073709551615 as signed); +cast(18446744073709551615 as signed) +-1 +select cast('18446744073709551615' as unsigned); +cast('18446744073709551615' as unsigned) +18446744073709551615 +select cast('18446744073709551615' as signed); +cast('18446744073709551615' as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('9223372036854775807' as signed); +cast('9223372036854775807' as signed) +9223372036854775807 +select cast(concat('184467440','73709551615') as unsigned); +cast(concat('184467440','73709551615') as unsigned) +18446744073709551615 +select cast(concat('184467440','73709551615') as signed); +cast(concat('184467440','73709551615') as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(repeat('1',20) as unsigned); +cast(repeat('1',20) as unsigned) +11111111111111111111 +select cast(repeat('1',20) as signed); +cast(repeat('1',20) as signed) +-7335632962598440505 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 23bba7d5aff..aeab81585f0 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -4,7 +4,6 @@ select CAST(1-2 AS UNSIGNED); select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); -select CONVERT('-1',UNSIGNED); select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; select ~5, cast(~5 as signed); @@ -22,6 +21,15 @@ select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +# out-of-range cases +select cast('18446744073709551616' as unsigned); +select cast('18446744073709551616' as signed); +select cast('9223372036854775809' as signed); +select cast('-1' as unsigned); +select cast('abc' as signed); +select cast('1a' as signed); +select cast('' as signed); + # # Character set convertion # @@ -118,3 +126,19 @@ select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour); select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00'); # Still we should not throw away "days" part of time value select timediff(cast('1 12:00:00' as time), '12:00:00'); + +# +# Bug #7036: Casting from string to unsigned would cap value of result at +# maximum signed value instead of maximum unsigned value +# +select cast(18446744073709551615 as unsigned); +select cast(18446744073709551615 as signed); +select cast('18446744073709551615' as unsigned); +select cast('18446744073709551615' as signed); +select cast('9223372036854775807' as signed); + +select cast(concat('184467440','73709551615') as unsigned); +select cast(concat('184467440','73709551615') as signed); + +select cast(repeat('1',20) as unsigned); +select cast(repeat('1',20) as signed); diff --git a/mysys/default.c b/mysys/default.c index 4ee2041bc39..bf23502389d 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -319,6 +319,56 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, /* + Skip over keyword and get argument after keyword + + SYNOPSIS + get_argument() + keyword Include directive keyword + kwlen Length of keyword + ptr Pointer to the keword in the line under process + line line number + + RETURN + 0 error + # Returns pointer to the argument after the keyword. +*/ + +static char *get_argument(const char *keyword, uint kwlen, + char *ptr, char *name, uint line) +{ + char *end; + + /* Skip over "include / includedir keyword" and following whitespace */ + + for (ptr+= kwlen - 1; + my_isspace(&my_charset_latin1, ptr[0]); + ptr++) + {} + + /* + Trim trailing whitespace from directory name + The -1 below is for the newline added by fgets() + Note that my_isspace() is true for \r and \n + */ + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; /* Cut off end space */ + + /* Print error msg if there is nothing after !include* directive */ + if (end <= ptr) + { + fprintf(stderr, + "error: Wrong '!%s' directive in config file: %s at line %d\n", + keyword, name, line); + return 0; + } + return ptr; +} + + +/* Open a configuration file (if exists) and read given options from it SYNOPSIS @@ -426,31 +476,10 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, sizeof(includedir_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) { - /* skip over "includedir" and following whitespace */ - for (ptr+= sizeof(includedir_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* - trim trailing whitespace from directory name - The -1 below is for the newline added by fgets() - Note that my_isspace() is true for \r and \n - */ - for (end= ptr + strlen(ptr) - 1; - my_isspace(&my_charset_latin1, *(end - 1)); - end--) - {} - end[0]= 0; - - /* print error msg if there is nothing after !includedir directive */ - if (end <= ptr) - { - fprintf(stderr, - "error: Wrong !includedir directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(includedir_keyword, + sizeof(includedir_keyword), + ptr, name, line))) + goto err; if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) goto err; @@ -486,26 +515,10 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) { - /* skip over `include' and following whitespace */ - for (ptr+= sizeof(include_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* trim trailing whitespace from filename */ - for (end= ptr + strlen(ptr) - 1; - my_isspace(&my_charset_latin1, *(end - 1)); - end--) - {} - end[0]= 0; - - if (end <= ptr) - { - fprintf(stderr, - "error: Wrong !include directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(include_keyword, + sizeof(include_keyword), ptr, + name, line))) + goto err; search_default_file_with_ext(args, alloc, "", "", ptr, group, recursion_level + 1); diff --git a/sql/field.h b/sql/field.h index 5dc124aba35..f19771c3f9c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -119,6 +119,7 @@ public: virtual String *val_str(String*,String *)=0; virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } + virtual Item_result cast_to_int_type () const { return result_type(); } static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) { return ptr == field->ptr && null_ptr == field->null_ptr; } @@ -1115,6 +1116,7 @@ public: } enum_field_types type() const { return FIELD_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } + enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/hostname.cc b/sql/hostname.cc index c74d230bbcb..fe2fad6f3b2 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -177,7 +177,14 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors) &tmp_errno))) { DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno)); - add_wrong_ip(in); + /* + Don't cache responses when the DSN server is down, as otherwise + transient DNS failure may leave any number of clients (those + that attempted to connect during the outage) unable to connect + indefinitely. + */ + if (tmp_errno == HOST_NOT_FOUND || tmp_error == NO_DATA) + add_wrong_ip(in); my_gethostbyname_r_free(); DBUG_RETURN(0); } diff --git a/sql/item.h b/sql/item.h index d949095b455..d576fbbc60a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -180,7 +180,8 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; - virtual Item_result result_type () const { return REAL_RESULT; } + virtual Item_result result_type() const { return REAL_RESULT; } + virtual Item_result cast_to_int_type() const { return result_type(); } virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ @@ -422,6 +423,10 @@ public: { return field->result_type(); } + Item_result cast_to_int_type() const + { + return field->cast_to_int_type(); + } enum_field_types field_type() const { return field->type(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 2b38584fe23..1b80ef06251 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -582,6 +582,58 @@ void Item_func_signed::print(String *str) } +longlong Item_func_signed::val_int_from_str(int *error) +{ + char buff[MAX_FIELD_WIDTH], *end; + String tmp(buff,sizeof(buff), &my_charset_bin), *res; + longlong value; + + /* + For a string result, we must first get the string and then convert it + to a longlong + */ + + if (!(res= args[0]->val_str(&tmp))) + { + null_value= 1; + *error= 0; + return 0; + } + null_value= 0; + end= (char*) res->ptr()+ res->length(); + value= my_strtoll10(res->ptr(), &end, error); + if (*error > 0 || end != res->ptr()+ res->length()) + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER", + res->c_ptr()); + return value; +} + + +longlong Item_func_signed::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (value < 0 && error == 0) + { + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to signed converted positive out-of-range integer to " + "it's negative complement"); + } + return value; +} + + void Item_func_unsigned::print(String *str) { str->append("cast(", 5); @@ -591,6 +643,27 @@ void Item_func_unsigned::print(String *str) } +longlong Item_func_unsigned::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (error < 0) + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to unsigned converted negative integer to it's " + "positive complement"); + return value; +} + + double Item_func_plus::val() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_func.h b/sql/item_func.h index 3a309f4ae99..288db3a148c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -226,12 +226,8 @@ public: null_value= args[0]->null_value; return tmp; } - longlong val_int() - { - longlong tmp= args[0]->val_int(); - null_value= args[0]->null_value; - return tmp; - } + longlong val_int(); + longlong val_int_from_str(int *error); void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } void print(String *str); @@ -245,6 +241,7 @@ public: const char *func_name() const { return "cast_as_unsigned"; } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } + longlong val_int(); void print(String *str); }; |