From 6483a71e82a06f857e702d9593aa9ad13cc94b85 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Wed, 6 Apr 2005 15:52:32 +0300 Subject: [PATCH 1/6] Fixed that create_time is set properly for cached threads --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d75efbd0b00..c76ccf5daf7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1488,6 +1488,7 @@ void end_thread(THD *thd, bool put_in_cache) thd=thread_cache.get(); thd->real_id=pthread_self(); (void) thd->store_globals(); + thd->thr_create_time= time(NULL); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; From 174c15aee1576113c2f778d6119ce9b2e4dcdc41 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Wed, 6 Apr 2005 16:52:41 +0300 Subject: [PATCH 2/6] Small fixes done while reviewing pushed code --- mysql-test/r/innodb-replace.result | 1 + mysql-test/t/innodb-replace.test | 4 ++++ sql/share/english/errmsg.txt | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb-replace.result b/mysql-test/r/innodb-replace.result index a27806640ad..b7edcc49e56 100644 --- a/mysql-test/r/innodb-replace.result +++ b/mysql-test/r/innodb-replace.result @@ -1,3 +1,4 @@ +drop table if exists t1; create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; select * from t1; c1 c2 stamp diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/t/innodb-replace.test index e7e96da1443..516f058a68e 100644 --- a/mysql-test/t/innodb-replace.test +++ b/mysql-test/t/innodb-replace.test @@ -2,6 +2,10 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + # # Bug #1078 # diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 3bfc83a4b41..1ae4e79bf01 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -67,7 +67,7 @@ character-set=latin1 "Column '%-.64s' cannot be null", "Unknown database '%-.64s'", "Table '%-.64s' already exists", -"Unknown table '%-.180s'", +"Unknown table '%-.100s'", "Column '%-.64s' in %-.64s is ambiguous", "Server shutdown in progress", "Unknown column '%-.64s' in '%-.64s'", From 972f86f1ee36c391a3de90a03513d7b65b8b4b42 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Tue, 26 Apr 2005 23:24:59 +0300 Subject: [PATCH 3/6] Cleanups during review --- mysys/default.c | 62 ++++++++++++++++++++++++++--------------------- sql/sql_insert.cc | 4 +-- sql/sql_select.cc | 12 +++++---- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/mysys/default.c b/mysys/default.c index 63323f15fd5..4ee2041bc39 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -402,33 +402,48 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, continue; /* Configuration File Directives */ - if ((*ptr == '!') && (recursion_level < max_recursion_level)) + if ((*ptr == '!')) { + if (recursion_level >= max_recursion_level) + { + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; + fprintf(stderr, + "Warning: skipping '%s' directive as maximum include" + "recursion level was reached in file %s at line %d\n", + ptr, name, line); + continue; + } + /* skip over `!' and following whitespace */ for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) {} - if ((!strncmp(ptr, includedir_keyword, sizeof(includedir_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) + if ((!strncmp(ptr, includedir_keyword, + 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 */ - end= ptr + strlen(ptr) - 1; - /* fgets() stores the newline character in the buffer */ - if ((end[0] == '\n') || (end[0] == '\r') || - my_isspace(&my_charset_latin1, end[0])) - { - for (; my_isspace(&my_charset_latin1, *(end - 1)); end--) - {} - end[0]= 0; - } + /* + 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) + if (end <= ptr) { fprintf(stderr, "error: Wrong !includedir directive in config " @@ -468,8 +483,8 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, my_dirend(search_dir); } - else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword) - 1])) + 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; @@ -477,12 +492,13 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, {} /* trim trailing whitespace from filename */ - end= ptr + strlen(ptr) - 1; - for (; my_isspace(&my_charset_latin1, *(end - 1)) ; end--) + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) {} end[0]= 0; - if (end == ptr) + if (end <= ptr) { fprintf(stderr, "error: Wrong !include directive in config " @@ -497,14 +513,6 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, continue; } - else - if (recursion_level >= max_recursion_level) - { - fprintf(stderr, - "warning: skipping !include directive as maximum include" - "recursion level was reached in file %s at line %d\n", - name, line); - } if (*ptr == '[') /* Group name */ { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7f890a583c6..f46c40f686a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -72,7 +72,7 @@ static int check_insert_fields(THD *thd, TABLE *table, List &fields, { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0), 1); + MYF(0), 1L); return -1; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -89,7 +89,7 @@ static int check_insert_fields(THD *thd, TABLE *table, List &fields, { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0), 1); + MYF(0), 1L); return -1; } TABLE_LIST table_list; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36efe26dff9..e7f968df396 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2055,8 +2055,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } } else if (old->eq_func && new_fields->eq_func && @@ -2068,8 +2068,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } else if (old->eq_func && new_fields->eq_func && (old->val->is_null() || new_fields->val->is_null())) @@ -2081,7 +2081,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, if (old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ - old->null_rejecting= false; + old->null_rejecting= 0; } else { @@ -2242,6 +2242,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, If the condition has form "tbl.keypart = othertbl.field" and othertbl.field can be NULL, there will be no matches if othertbl.field has NULL value. + We use null_rejecting in add_not_null_conds() to add + 'othertbl.field IS NOT NULL' to tab->select_cond. */ (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && From e18a155fd67913e7c34628d4ce235ba3f1d504fc Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Wed, 27 Apr 2005 14:31:04 +0300 Subject: [PATCH 4/6] Fixed core dump bug when hot link list in key cache was empty. Bug #10167 --- mysql-test/r/drop.result | 4 +- mysys/mf_keycache.c | 11 +- tests/index_corrupt.pl | 212 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+), 6 deletions(-) create mode 100755 tests/index_corrupt.pl diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 40dda86b729..b07cf16aa64 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -30,13 +30,13 @@ table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' drop table table1, table2, table3, table4, table5, table6, table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28, table29, table30; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' use test; drop database mysqltest; flush tables with read lock; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 9feaf8dcd57..cee1b7eb4e9 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1025,8 +1025,8 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count) for a too long time (this time is determined by parameter age_threshold). */ -static inline void unreg_request(KEY_CACHE *keycache, - BLOCK_LINK *block, int at_end) +static void unreg_request(KEY_CACHE *keycache, + BLOCK_LINK *block, int at_end) { if (! --block->requests) { @@ -1045,10 +1045,13 @@ static inline void unreg_request(KEY_CACHE *keycache, } link_block(keycache, block, hot, (my_bool)at_end); block->last_hit_time= keycache->keycache_time; - if (++keycache->keycache_time - keycache->used_ins->last_hit_time > + keycache->keycache_time++; + + block= keycache->used_ins; + /* Check if we should link a hot block to the warm block */ + if (block && keycache->keycache_time - block->last_hit_time > keycache->age_threshold) { - block= keycache->used_ins; unlink_block(keycache, block); link_block(keycache, block, 0, 0); if (block->temperature != BLOCK_WARM) diff --git a/tests/index_corrupt.pl b/tests/index_corrupt.pl new file mode 100755 index 00000000000..19bf54f5d11 --- /dev/null +++ b/tests/index_corrupt.pl @@ -0,0 +1,212 @@ +#!/usr/bin/perl -w +# +# This is a test for a key cache bug (bug #10167) +# To expose the bug mysqld should be started with --key-buffer-size=64K +# + +$opt_loop_count=100000; # Change this to make test harder/easier + +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +package main; + +$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert= + $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0; +$opt_host=$opt_user=$opt_password=""; $opt_db="test"; + +GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in", + "skip-delete","verbose","fast-insert","lock-tables","debug","fast", + "force","user=s","password=s") || die "Aborted"; +$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these + +$firsttable = "bench_f1"; +$secondtable = "bench_f2"; +$kill_file= "/tmp/mysqltest_index_corrupt.$$"; + +#### +#### Start timeing and start test +#### + +$start_time=new Benchmark; +if (!$opt_skip_create) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table if exists $firsttable, $secondtable"); + + print "Creating tables in $opt_db\n"; + $dbh->do("create table $firsttable ( +c_pollid INTEGER NOT NULL, +c_time BIGINT NOT NULL, +c_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_r_i1 (c_pollid), +INDEX t_mgmt_hist_r_i2 (c_time), +INDEX t_mgmt_hist_r_i3 (c_rolled_up))") or die $DBI::errstr; + + $dbh->do("create table $secondtable ( +c_pollid INTEGER NOT NULL, +c_min_time BIGINT NOT NULL, +c_max_time BIGINT NOT NULL, +c_min_data DOUBLE NOT NULL, +c_max_data DOUBLE NOT NULL, +c_avg_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_d_i1 (c_pollid), +INDEX t_mgmt_hist_d_i2 (c_min_time), +INDEX t_mgmt_hist_d_i3 (c_max_time), +INDEX t_mgmt_hist_d_i4 (c_rolled_up))") or die $DBI::errstr; + + + $dbh->disconnect; $dbh=0; # Close handler +} +$|= 1; # Autoflush + +#### +#### Start the tests +#### + +print "Running tests\n"; +insert_in_bench() if (($pid=fork()) == 0); $work{$pid}="insert"; +select_from_bench() if (($pid=fork()) == 0); $work{$pid}="insert-select; +delete_from_bench() if (($pid=fork()) == 0); $work{$pid}="delete"; + +$errors=0; +while (($pid=wait()) != -1) +{ + $ret=$?/256; + print "thread '" . $work{$pid} . "' finished with exit code $ret\n"; + $errors++ if ($ret != 0); +} + +if (!$opt_skip_delete && !$errors) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table $firsttable, $secondtable"); +} +print ($errors ? "Test failed\n" :"Test ok\n"); + +$end_time=new Benchmark; +print "Total time: " . + timestr(timediff($end_time, $start_time),"noc") . "\n"; + +unlink $kill_file; + +exit(0); + +# +# Insert records in the two tables +# + +sub insert_in_bench +{ + my ($dbh,$rows,$found,$i); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows <= $opt_loop_count ; $rows++) + { + $c_pollid = sprintf("%d",rand 1000); + $c_time = sprintf("%d",rand 100000); + $c_data = rand 1000000; + $test = rand 1; + $c_error=0; + $c_warning=0; + $c_okay=0; + $c_unknown=0; + if ($test < .8) { + $c_okay=1; + } elsif ($test <.9) { + $c_error=1; + } elsif ($test <.95) { + $c_warning=1; + } else { + $c_unknown=1; + } + $statement = "INSERT INTO $firsttable (c_pollid, c_time, c_data, c_error +, c_warning, c_okay, c_unknown, c_rolled_up) ". + "VALUES ($c_pollid,$c_time,$c_data,$c_error,$c_warning,$c_okay,$c_unknown,0)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + } + + $dbh->disconnect; $dbh=0; + print "insert_in_bench: Inserted $rows rows\n"; + + # Kill other threads + open(KILLFILE, "> $kill_file"); + close(KILLFILE); + + exit(0); +} + + +sub select_from_bench +{ + my ($dbh,$rows,$cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 100000; + $t_value2 = $t_value+10000; + $statement = "INSERT INTO $secondtable (c_pollid, c_min_time, c_max_time +, c_min_data, c_max_data, c_avg_data, c_error, c_warning, c_okay, c_unknown, c_rolled_up) SELECT c_pollid, MIN(c_time), MAX(c_time), MIN(c_data), MAX(c_data), AVG(c_data), SUM(c_error), SUM(c_warning), SUM(c_okay), SUM(c_unknown), 0 FROM $firsttable WHERE (c_time>=$t_value) AND (c_time<$t_value2) AND (c_rolled_up=0) GROUP BY c_pollid"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 1; + if (-e $kill_file) + { + last; + } + } + print "select_from_bench: insert-select executed $rows times\n"; + exit(0); +} + + +sub delete_from_bench +{ + my ($dbh,$row, $t_value, $t2_value, $statement, $cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 50000; + $t2_value = $t_value + 50001; + $statement = "DELETE FROM $firsttable WHERE (c_time>$t_value) AND (c_time<$t2_value)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 10; + if (-e $kill_file) + { + last; + } + } + print "delete: delete executed $rows times\n"; + exit(0); +} From fbf31c4a8c68419c689c52c031a98275755a0961 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Fri, 29 Apr 2005 17:03:34 +0300 Subject: [PATCH 5/6] 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 | 3 ++ include/config-win.h | 17 ++++++- include/my_global.h | 2 + mysql-test/r/cast.result | 71 +++++++++++++++++++++++++-- mysql-test/t/cast.test | 26 +++++++++- mysys/default.c | 103 ++++++++++++++++++++++----------------- sql/field.h | 2 + sql/hostname.cc | 9 +++- sql/item.h | 7 ++- sql/item_func.cc | 73 +++++++++++++++++++++++++++ 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 ]) +AC_CHECK_TYPES([size_t], [], [], [#include ]) + 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 @@ -318,6 +318,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 @@ -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); }; From b11705a2b02677766d56f0d25575db14af66aca9 Mon Sep 17 00:00:00 2001 From: "evgen@moonbone.local" <> Date: Fri, 29 Apr 2005 21:19:39 +0400 Subject: [PATCH 6/6] Fix bug #9703 "Error 1032 with GROUP BY query and large tables" Reset old error if tmp table was successfully created. Test data is large and can be found in bug report along with test query. --- BitKeeper/etc/logging_ok | 2 ++ sql/sql_select.cc | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e4de8c6ebf2..330d28daf52 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -45,6 +45,8 @@ dlenev@build.mysql.com dlenev@jabberwock.localdomain dlenev@mysql.com ejonore@mc03.ndb.mysql.com +evgen@moonbone.(none) +evgen@moonbone.local gbichot@quadita2.mysql.com gbichot@quadxeon.mysql.com georg@beethoven.local diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36efe26dff9..96958db2cce 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6891,6 +6891,11 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), &join->tmp_table_param, error, 0)) DBUG_RETURN(-1); + /* + If table->file->write_row() was failed because of 'out of memory' + and tmp table succesfully created, reset error. + */ + error=0; } if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) {