From e0691da0c199ab2c65f4c9fb9681e4292c224a14 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 15 Oct 2007 10:34:34 +0400 Subject: [PATCH 01/44] Fix for bug #30453: String not cast to int correctly. Problem: my_strntoull10rnd_8bit() handled incorrectly cases when the input string contains a decimal point and is long enough to overrun the 'unsigned long long' type. The position of the decimal point was not taken into account which resulted in miscalculated numbers and truncation to appropriate SQL data type limits. Solution: Fix my_strntoull10rnd_8bit() to take the position of a decimal point into account in such cases. --- mysql-test/r/insert.result | 14 ++++++++++++++ mysql-test/t/insert.test | 15 +++++++++++++++ strings/ctype-simple.c | 14 +++++++++----- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 8a0a3ba848c..e1cad814226 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -461,4 +461,18 @@ i 2 2 DROP TABLE t1, t2; +CREATE TABLE t1 (c1 INT NOT NULL); +INSERT INTO t1 VALUES(4188.32999999999992724042385816574096679687500), +('4188.32999999999992724042385816574096679687500'), (4188); +SELECT * FROM t1; +c1 +4188 +4188 +4188 +CREATE TABLE t2 (c1 BIGINT); +INSERT INTO t2 VALUES('15449237462.0000000000'); +SELECT * FROM t2; +c1 +15449237462 +DROP TABLE t1, t2; End of 5.0 tests. diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 76177403bd0..c36408a52fe 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -353,5 +353,20 @@ SELECT * FROM t2; DROP TABLE t1, t2; +# +# Bug #30453: String not cast to int correctly +# + +CREATE TABLE t1 (c1 INT NOT NULL); +INSERT INTO t1 VALUES(4188.32999999999992724042385816574096679687500), +('4188.32999999999992724042385816574096679687500'), (4188); +SELECT * FROM t1; + +CREATE TABLE t2 (c1 BIGINT); +INSERT INTO t2 VALUES('15449237462.0000000000'); +SELECT * FROM t2; + +DROP TABLE t1, t2; + --echo End of 5.0 tests. diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 8b1b0d6790d..e073262cd4c 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1538,14 +1538,18 @@ my_strntoull10rnd_8bit(CHARSET_INFO *cs __attribute__((unused)), } else addon= (*str >= '5'); - for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++) + if (!dot) { - if (!dot) - shift++; + for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; shift++, str++); + if (str < end && *str == '.') + { + str++; + for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++); + } } - if (str < end && *str == '.' && !dot) + else { - str++; + shift= dot - str; for ( ; str < end && (ch= (unsigned char) (*str - '0')) < 10; str++); } goto exp; From 0dfe3a8dfbcba14d4ccdf09cfe88d59f98fee741 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 16 Oct 2007 13:43:16 +0500 Subject: [PATCH 02/44] Fix for bug #31285: main.status test fails with different Table_locks_waited Problem: Table_locks_waited value may depend on general logging. Fix: switch general logging off. --- mysql-test/r/status.result | 3 +++ mysql-test/t/status.test | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index db75044ee5d..c95b09597fc 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -8,6 +8,8 @@ VARIABLE_NAME VARIABLE_VALUE TABLE_LOCKS_IMMEDIATE 2 TABLE_LOCKS_WAITED 0 SET SQL_LOG_BIN=0; +set @old_general_log = @@global.general_log; +set global general_log = 'OFF'; drop table if exists t1; create table t1(n int) engine=myisam; insert into t1 values(1); @@ -20,6 +22,7 @@ show status like 'Table_locks_waited'; Variable_name Value Table_locks_waited 1 drop table t1; +set global general_log = @old_general_log; select 1; 1 1 diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 1cd5aa1726a..6a11791924a 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -21,6 +21,8 @@ select * from information_schema.session_status where variable_name like 'Table_ connection con1; # ++Immediate = 3 SET SQL_LOG_BIN=0; +set @old_general_log = @@global.general_log; +set global general_log = 'OFF'; --disable_warnings # ++Immediate = 4 drop table if exists t1; @@ -60,6 +62,7 @@ reap; # ++Immediate = 16 + $wait_condition_reps show status like 'Table_locks_waited'; drop table t1; +set global general_log = @old_general_log; disconnect con2; disconnect con1; From 3d2f493fb42001aac3706b838d8c8bc9f651538e Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 16 Oct 2007 17:19:07 +0500 Subject: [PATCH 03/44] Fix bug #31604: server crash when setting slow_query_log_file/global general_log_file variable Problem: we don't evaluate given expression checking values of the slow_query_log_file/general_log_file, don't check it for NULL. Fix: evaluate the expression, check result returned. --- mysql-test/r/log_state.result | 13 +++++++++++++ mysql-test/t/log_state.test | 20 ++++++++++++++++++++ sql/set_var.cc | 23 +++++++++++++++++------ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result index 3a3ef584ce3..407d93cf321 100644 --- a/mysql-test/r/log_state.result +++ b/mysql-test/r/log_state.result @@ -175,3 +175,16 @@ SET GLOBAL slow_query_log = ON; SET GLOBAL READ_ONLY = OFF; SET GLOBAL general_log = @old_general_log_state; SET GLOBAL slow_query_log = @old_slow_log_state; +set @old_general_log_file= @@global.general_log_file; +set @old_slow_query_log_file= @@global.slow_query_log_file; +set global general_log_file= concat('/not exiting path/log.maste', 'r'); +ERROR 42000: Variable 'general_log_file' can't be set to the value of '/not exiting path/log.master' +set global general_log_file= NULL; +ERROR 42000: Variable 'general_log_file' can't be set to the value of 'NULL' +set global slow_query_log_file= concat('/not exiting path/log.maste', 'r'); +ERROR 42000: Variable 'slow_query_log_file' can't be set to the value of '/not exiting path/log.master' +set global slow_query_log_file= NULL; +ERROR 42000: Variable 'slow_query_log_file' can't be set to the value of 'NULL' +set global general_log_file= @old_general_log_file; +set global slow_query_log_file= @old_slow_query_log_file; +End of 5.1 tests diff --git a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test index c67da261ef1..ec3644cbff1 100644 --- a/mysql-test/t/log_state.test +++ b/mysql-test/t/log_state.test @@ -189,3 +189,23 @@ disconnect con1; # Remove the log files that was created in the "default location" # i.e var/run --remove_file $MYSQLTEST_VARDIR/run/master.log + +# +# Bug #31604: server crash when setting slow_query_log_file/general_log_file +# +set @old_general_log_file= @@global.general_log_file; +set @old_slow_query_log_file= @@global.slow_query_log_file; + +--error 1231 +set global general_log_file= concat('/not exiting path/log.maste', 'r'); +--error 1231 +set global general_log_file= NULL; +--error 1231 +set global slow_query_log_file= concat('/not exiting path/log.maste', 'r'); +--error 1231 +set global slow_query_log_file= NULL; + +set global general_log_file= @old_general_log_file; +set global slow_query_log_file= @old_slow_query_log_file; + +--echo End of 5.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index ec82b56d793..c26e9a8d6e2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2102,18 +2102,24 @@ void sys_var_log_state::set_default(THD *thd, enum_var_type type) static int sys_check_log_path(THD *thd, set_var *var) { - char path[FN_REFLEN]; + char path[FN_REFLEN], buff[FN_REFLEN]; MY_STAT f_stat; - const char *var_path= var->value->str_value.ptr(); + String str(buff, sizeof(buff), system_charset_info), *res; + const char *log_file_str; + + if (!(res= var->value->val_str(&str))) + goto err; + + log_file_str= res->c_ptr(); bzero(&f_stat, sizeof(MY_STAT)); - (void) unpack_filename(path, var_path); + (void) unpack_filename(path, log_file_str); if (my_stat(path, &f_stat, MYF(0))) { /* Check if argument is a file and we have 'write' permission */ if (!MY_S_ISREG(f_stat.st_mode) || !(f_stat.st_mode & MY_S_IWRITE)) - return -1; + goto err; } else { @@ -2122,11 +2128,16 @@ static int sys_check_log_path(THD *thd, set_var *var) Check if directory exists and we have permission to create file & write to file */ - (void) dirname_part(path, var_path, &path_length); + (void) dirname_part(path, log_file_str, &path_length); if (my_access(path, (F_OK|W_OK))) - return -1; + goto err; } return 0; + +err: + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, + res ? log_file_str : "NULL"); + return 1; } From ffde32d219d7824257efc98476c310bf3ffac06b Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 17 Oct 2007 14:28:00 +0500 Subject: [PATCH 04/44] Fix for bug#31615: crash after set names ucs2 collate xxx Problem: currently, UCS-2 cannot be used as a client character set. Fix: raise an error if one attempts to set it to USC-2. --- mysql-test/r/ctype_ucs.result | 8 ++++++++ mysql-test/t/ctype_ucs.test | 12 ++++++++++++ sql/set_var.cc | 22 ++++++++++++++++++++++ sql/set_var.h | 1 + 4 files changed, 43 insertions(+) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index bf827209795..befbd04f63d 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -803,4 +803,12 @@ quote(name) ???????? ???????????????? drop table bug20536; +set names ucs2; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set names ucs2 collate ucs2_bin; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set character_set_client= ucs2; +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' +set character_set_client= concat('ucs', substr('2', 1)); +ERROR 42000: Variable 'character_set_client' can't be set to the value of 'ucs2' End of 4.1 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 10559d33eb3..9e6bd0e95e6 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -535,4 +535,16 @@ select quote(name) from bug20536; drop table bug20536; +# +# Bug #31615: crash after set names ucs2 collate xxx +# +--error 1231 +set names ucs2; +--error 1231 +set names ucs2 collate ucs2_bin; +--error 1231 +set character_set_client= ucs2; +--error 1231 +set character_set_client= concat('ucs', substr('2', 1)); + --echo End of 4.1 tests diff --git a/sql/set_var.cc b/sql/set_var.cc index 520ee5c9f70..275252c4960 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1992,6 +1992,21 @@ void sys_var_character_set_client::set_default(THD *thd, enum_var_type type) } +bool sys_var_character_set_client::check(THD *thd, set_var *var) +{ + if (sys_var_character_set::check(thd, var)) + return 1; + /* Currently, UCS-2 cannot be used as a client character set */ + if (var->save_result.charset->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->save_result.charset->csname); + return 1; + } + return 0; +} + + CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type) { @@ -2355,6 +2370,13 @@ end: int set_var_collation_client::check(THD *thd) { + /* Currently, UCS-2 cannot be used as a client character set */ + if (character_set_client->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + character_set_client->csname); + return 1; + } return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index 78b34963e9d..f6fd0a082b5 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -578,6 +578,7 @@ public: sys_var_character_set(name_arg) {} void set_default(THD *thd, enum_var_type type); CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); + bool check(THD *thd, set_var *var); }; class sys_var_character_set_results :public sys_var_character_set From 6d1f3e8de56e3cc861272265fc1f6119a41036a9 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 17 Oct 2007 20:08:58 +0400 Subject: [PATCH 05/44] Fix for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compile The bug is a combination of two problems: 1. IA64/ICC MySQL binaries use glibc's qsort(), not the one in mysys. 2. The order relation implemented by join_tab_cmp() is not transitive, i.e. it is possible to choose such a, b and c that (a < b) && (b < c) but (c < a). This implies that result of a sort using the relation implemented by join_tab_cmp() depends on the order in which elements are compared, i.e. the result is implementation-specific. Since choose_plan() uses qsort() to pre-sort the join tables using join_tab_cmp() as a compare function, the results of the sorting may vary depending on qsort() implementation. It is neither possible nor important to implement a better ordering algorithm in join_tab_cmp(). Therefore the only way to fix it is to force our own qsort() to be used by renaming it to my_qsort(), so we don't depend on linker to decide that. This patch also "fixes" bug #20530: qsort redefinition violates the standard. --- include/my_sys.h | 6 ++++-- libmysql/Makefile.shared | 2 +- myisam/ft_boolean_search.c | 4 ++-- myisam/ft_nlq_search.c | 3 ++- myisam/myisampack.c | 2 +- myisam/sort.c | 12 ++++++------ mysys/mf_keycache.c | 2 +- mysys/mf_qsort.c | 4 ++-- mysys/mf_sort.c | 2 +- mysys/my_lib.c | 6 +++--- mysys/queues.c | 4 ++-- sql/examples/ha_tina.cc | 2 +- sql/item_cmpfunc.cc | 2 +- sql/item_cmpfunc.h | 2 +- sql/opt_range.cc | 8 ++++---- sql/records.cc | 3 ++- sql/sql_acl.cc | 20 ++++++++++---------- sql/sql_array.h | 2 +- sql/sql_help.cc | 2 +- sql/sql_select.cc | 18 +++++++++++++++--- sql/sql_table.cc | 2 +- 21 files changed, 62 insertions(+), 46 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 4f7e75a836e..d401cfca082 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -709,8 +709,10 @@ extern sig_handler my_set_alarm_variable(int signo); extern void my_string_ptr_sort(void *base,uint items,size_s size); extern void radixsort_for_str_ptr(uchar* base[], uint number_of_elements, size_s size_of_element,uchar *buffer[]); -extern qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, - qsort2_cmp cmp, void *cmp_argument); +extern qsort_t my_qsort(void *base_ptr, size_t total_elems, size_t size, + qsort_cmp cmp); +extern qsort_t my_qsort2(void *base_ptr, size_t total_elems, size_t size, + qsort2_cmp cmp, void *cmp_argument); extern qsort2_cmp get_ptr_compare(uint); void my_store_ptr(byte *buff, uint pack_length, my_off_t pos); my_off_t my_get_ptr(byte *ptr, uint pack_length); diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index dc6d658fcdf..5947ae26486 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -73,7 +73,7 @@ sqlobjects = net.lo sql_cmn_objects = pack.lo client.lo my_time.lo # Not needed in the minimum library -mysysobjects2 = my_lib.lo +mysysobjects2 = my_lib.lo mf_qsort.lo mysysobjects = $(mysysobjects1) $(mysysobjects2) target_libadd = $(mysysobjects) $(mystringsobjects) $(dbugobjects) \ $(sql_cmn_objects) $(vio_objects) $(sqlobjects) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 9f442148069..57de75ee4be 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -430,8 +430,8 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, sizeof(FTB_WORD *)*ftb->queue.elements); memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements); - qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *), - (qsort2_cmp)FTB_WORD_cmp_list, ftb->charset); + my_qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *), + (qsort2_cmp)FTB_WORD_cmp_list, ftb->charset); if (ftb->queue.elements<2) ftb->with_scan &= ~FTB_FLAG_TRUNC; ftb->state=READY; return ftb; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index f63735b7e68..41d145c070f 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -281,7 +281,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, &dptr, left_root_right); if (flags & FT_SORTED) - qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, 0); + my_qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, + 0); err: delete_tree(&aio.dtree); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 4ead51639f3..fa58211ea88 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -3148,7 +3148,7 @@ static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count) cur_sort_p= sort_counts; while (cur_count_p < end_count_p) *(cur_sort_p++)= cur_count_p++; - (void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp); + (void) my_qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp); /* Assign faked counts. diff --git a/myisam/sort.c b/myisam/sort.c index f48161b7c8e..c44b05313b0 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -649,8 +649,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, uint sort_length=info->key_length; DBUG_ENTER("write_keys"); - qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info); + my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, + info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) @@ -692,8 +692,8 @@ static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info, int err; DBUG_ENTER("write_keys_varlen"); - qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info); + my_qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, + info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) @@ -735,8 +735,8 @@ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, { DBUG_ENTER("write_index"); - qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*), - (qsort2_cmp) info->key_cmp,info); + my_qsort2((gptr) sort_keys,(size_t) count,sizeof(byte*), + (qsort2_cmp) info->key_cmp,info); while (count--) { if ((*info->key_write)(info,*sort_keys++)) diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 83363e6960d..baf3bffccb8 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -2268,7 +2268,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache, As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH we are guarunteed no thread will change them */ - qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link); + my_qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link); keycache_pthread_mutex_lock(&keycache->cache_lock); for ( ; cache != end ; cache++) diff --git a/mysys/mf_qsort.c b/mysys/mf_qsort.c index 3d52d56c952..4b3ecb603a6 100644 --- a/mysys/mf_qsort.c +++ b/mysys/mf_qsort.c @@ -91,10 +91,10 @@ typedef struct st_stack *****************************************************************************/ #ifdef QSORT_EXTRA_CMP_ARGUMENT -qsort_t qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp, +qsort_t my_qsort2(void *base_ptr, size_t count, size_t size, qsort2_cmp cmp, void *cmp_argument) #else -qsort_t qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp) +qsort_t my_qsort(void *base_ptr, size_t count, size_t size, qsort_cmp cmp) #endif { char *low, *high, *pivot; diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c index e7fd6873eee..a0c74642cb0 100644 --- a/mysys/mf_sort.c +++ b/mysys/mf_sort.c @@ -35,7 +35,7 @@ void my_string_ptr_sort(void *base, uint items, size_s size) if (size && items) { uint size_arg=size; - qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg); + my_qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg); } } } diff --git a/mysys/my_lib.c b/mysys/my_lib.c index 61de4ff9065..a076a0c971d 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -187,7 +187,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_RETURN(result); @@ -498,7 +498,7 @@ MY_DIR *my_dir(const char *path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_PRINT("exit", ("found %d files", result->number_off_files)); DBUG_RETURN(result); @@ -605,7 +605,7 @@ MY_DIR *my_dir(const char* path, myf MyFlags) result->number_off_files= dir_entries_storage->elements; if (!(MyFlags & MY_DONT_SORT)) - qsort((void *) result->dir_entry, result->number_off_files, + my_qsort((void *) result->dir_entry, result->number_off_files, sizeof(FILEINFO), (qsort_cmp) comp_names); DBUG_RETURN(result); diff --git a/mysys/queues.c b/mysys/queues.c index 7809c97131c..6b88420a1cd 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -250,6 +250,6 @@ static int queue_fix_cmp(QUEUE *queue, void **a, void **b) void queue_fix(QUEUE *queue) { - qsort2(queue->root+1,queue->elements, sizeof(void *), - (qsort2_cmp)queue_fix_cmp, queue); + my_qsort2(queue->root+1,queue->elements, sizeof(void *), + (qsort2_cmp)queue_fix_cmp, queue); } diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 2c5226222e2..0d1d821cf17 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -852,7 +852,7 @@ int ha_tina::rnd_end() It also sorts so that we move the final blocks to the beginning so that we move the smallest amount of data possible. */ - qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); + my_qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set); for (ptr= chain; ptr < chain_ptr; ptr++) { memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..45ed61a2ab7 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2775,7 +2775,7 @@ static inline int cmp_ulongs (ulonglong a_val, ulonglong b_val) SYNOPSIS cmp_longlong() - cmp_arg an argument passed to the calling function (qsort2) + cmp_arg an argument passed to the calling function (my_qsort2) a left argument b right argument diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..2ea155b3fac 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -781,7 +781,7 @@ public: virtual byte *get_value(Item *item)=0; void sort() { - qsort2(base,used_count,size,compare,collation); + my_qsort2(base,used_count,size,compare,collation); } int find(Item *item); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 04e2816d553..c3e9b6638bd 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3159,8 +3159,8 @@ TRP_ROR_INTERSECT *get_best_ror_intersect(const PARAM *param, SEL_TREE *tree, ROR_SCAN_INFO's. Step 2: Get best ROR-intersection using an approximate algorithm. */ - qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info); + my_qsort(tree->ror_scans, tree->n_ror_scans, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info); DBUG_EXECUTE("info",print_ror_scans_arr(param->table, "ordered", tree->ror_scans, tree->ror_scans_end);); @@ -3349,8 +3349,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, bitmap_get_first(&(*scan)->covered_fields); } - qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), - (qsort_cmp)cmp_ror_scan_info_covering); + my_qsort(ror_scan_mark, ror_scans_end-ror_scan_mark, sizeof(ROR_SCAN_INFO*), + (qsort_cmp)cmp_ror_scan_info_covering); DBUG_EXECUTE("info", print_ror_scans_arr(param->table, "remaining scans", diff --git a/sql/records.cc b/sql/records.cc index 3a833c87b7b..f61efc13034 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -497,7 +497,8 @@ static int rr_from_cache(READ_RECORD *info) int3store(ref_position,(long) i); ref_position+=3; } - qsort(info->read_positions,length,info->struct_length,(qsort_cmp) rr_cmp); + my_qsort(info->read_positions, length, info->struct_length, + (qsort_cmp) rr_cmp); position=info->read_positions; for (i=0 ; i < length ; i++) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f9bd2c6ba0d..d5257b1076a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -248,8 +248,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_hosts,(gptr) &host)); } - qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, - sizeof(ACL_HOST),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements, + sizeof(ACL_HOST),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_hosts); @@ -421,8 +421,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) allow_all_hosts=1; // Anyone can connect } } - qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_users); @@ -479,8 +479,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) #endif VOID(push_dynamic(&acl_dbs,(gptr) &db)); } - qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); end_read_record(&read_record_info); freeze_size(&acl_dbs); init_check_host(); @@ -1110,8 +1110,8 @@ static void acl_insert_user(const char *user, const char *host, if (!acl_user.host.hostname || (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1])) allow_all_hosts=1; // Anyone can connect /* purecov: tested */ - qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, - sizeof(ACL_USER),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, + sizeof(ACL_USER),(qsort_cmp) acl_compare); /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ rebuild_check_host(); @@ -1173,8 +1173,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db, acl_db.access=privileges; acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user); VOID(push_dynamic(&acl_dbs,(gptr) &acl_db)); - qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, - sizeof(ACL_DB),(qsort_cmp) acl_compare); + my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements, + sizeof(ACL_DB),(qsort_cmp) acl_compare); } diff --git a/sql/sql_array.h b/sql/sql_array.h index e2e12bee241..dcef457dce7 100644 --- a/sql/sql_array.h +++ b/sql/sql_array.h @@ -62,7 +62,7 @@ public: void sort(CMP_FUNC cmp_func) { - qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); + my_qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func); } }; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index ba7f1a534ea..69a257a9d37 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -524,7 +524,7 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, List_iterator it(*names); for (pos= pointers; pos!=end; (*pos++= it++)); - qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); + my_qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); for (pos= pointers; pos!=end; pos++) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d11f23d854..b519c06420f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3658,7 +3658,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, { KEYUSE key_end,*prev,*save_pos,*use; - qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), + my_qsort(keyuse->buffer,keyuse->elements,sizeof(KEYUSE), (qsort_cmp) sort_keyuse); bzero((char*) &key_end,sizeof(key_end)); /* Add for easy testing */ @@ -4371,8 +4371,9 @@ choose_plan(JOIN *join, table_map join_tables) Apply heuristic: pre-sort all access plans with respect to the number of records accessed. */ - qsort(join->best_ref + join->const_tables, join->tables - join->const_tables, - sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp); + my_qsort(join->best_ref + join->const_tables, + join->tables - join->const_tables, sizeof(JOIN_TAB*), + straight_join ? join_tab_cmp_straight : join_tab_cmp); if (straight_join) { @@ -4421,6 +4422,17 @@ choose_plan(JOIN *join, table_map join_tables) ptr1 pointer to first JOIN_TAB object ptr2 pointer to second JOIN_TAB object + NOTES + The order relation implemented by join_tab_cmp() is not transitive, + i.e. it is possible to choose such a, b and c that (a < b) && (b < c) + but (c < a). This implies that result of a sort using the relation + implemented by join_tab_cmp() depends on the order in which + elements are compared, i.e. the result is implementation-specific. + Example: + a: dependent = 0x0 table->map = 0x1 found_records = 3 ptr = 0x907e6b0 + b: dependent = 0x0 table->map = 0x2 found_records = 3 ptr = 0x907e838 + c: dependent = 0x6 table->map = 0x10 found_records = 2 ptr = 0x907ecd0 + RETURN 1 if first is bigger -1 if second is bigger diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6cbe98fe862..b6e41788ef0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1476,7 +1476,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } /* Sort keys in optimized order */ - qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), + my_qsort((gptr) *key_info_buffer, *key_count, sizeof(KEY), (qsort_cmp) sort_keys); create_info->null_bits= null_fields; From 04b1c9ca40edcce1dc0dfcc00b65a0971efb18f8 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 18 Oct 2007 15:17:21 +0400 Subject: [PATCH 06/44] Post-merge changes for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compiler. --- include/my_sys.h | 2 +- sql/partition_info.cc | 4 ++-- sql/set_var.cc | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index e919ed75541..638b1f4a2d4 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -784,7 +784,7 @@ extern int get_index_dynamic(DYNAMIC_ARRAY *array, uchar * element); #define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index)) #define push_dynamic(A,B) insert_dynamic((A),(B)) #define reset_dynamic(array) ((array)->elements= 0) -#define sort_dynamic(A,cmp) qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) +#define sort_dynamic(A,cmp) my_qsort((A)->buffer, (A)->elements, (A)->size_of_element, (cmp)) extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str, size_t init_alloc,size_t alloc_increment); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ab887d5dda0..86d50cdf524 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -666,8 +666,8 @@ bool partition_info::check_list_constants() if (fixed && no_list_values) { bool first= TRUE; - qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), - &list_part_cmp); + my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), + &list_part_cmp); i= 0; LINT_INIT(prev_value); diff --git a/sql/set_var.cc b/sql/set_var.cc index ec82b56d793..9a6ad9ce662 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2900,7 +2900,8 @@ SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted) /* sort into order */ if (sorted) - qsort(result, count + fixed_count, sizeof(SHOW_VAR), (qsort_cmp)show_cmp); + my_qsort(result, count + fixed_count, sizeof(SHOW_VAR), + (qsort_cmp) show_cmp); /* make last element empty */ bzero(show, sizeof(SHOW_VAR)); From 525fe23acd6772f92ed1bd7840eff2fbbc862e6d Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 18 Oct 2007 21:48:16 +0200 Subject: [PATCH 07/44] Remove unportable use of "system rm" --- mysql-test/t/binlog_killed.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/binlog_killed.test b/mysql-test/t/binlog_killed.test index 034895f17cb..e0b2f0a3db6 100644 --- a/mysql-test/t/binlog_killed.test +++ b/mysql-test/t/binlog_killed.test @@ -242,7 +242,7 @@ drop function bug27563; drop function bug27565; } -system rm $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; +remove_file $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog ; drop table t1,t2,t3; From b4f558419ff3b603fbd29adfa085f2d2c8f4b379 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Fri, 19 Oct 2007 14:54:05 +0500 Subject: [PATCH 08/44] Fix for bug #31349: ERROR 1062 (23000): Duplicate entry '' for key 'group_key' Problem: lying to the optimizer that a function (Item_func_inet_ntoa) cannot return NULL values leads to unexpected results (in the case group keys creation/comparison is broken). Fix: Item_func_inet_ntoa::maybe_null should be set properly. --- mysql-test/r/func_misc.result | 6 ++++++ mysql-test/t/func_misc.test | 8 ++++++++ sql/item_strfunc.h | 7 ++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 35101e26ff6..db2490bd261 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -185,4 +185,10 @@ ERROR 21000: Operand should contain 1 column(s) drop table table_26093; drop function func_26093_a; drop function func_26093_b; +create table t1 (a int not null); +insert into t1 values (-1), (-2); +select min(a) from t1 group by inet_ntoa(a); +min(a) +-2 +drop table t1; End of 5.0 tests diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index 8ff62f68e45..5a70daa50e8 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -189,4 +189,12 @@ drop table table_26093; drop function func_26093_a; drop function func_26093_b; +# +# Bug #31349: ERROR 1062 (23000): Duplicate entry '' for key 'group_key' +# +create table t1 (a int not null); +insert into t1 values (-1), (-2); +select min(a) from t1 group by inet_ntoa(a); +drop table t1; + --echo End of 5.0 tests diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6ca0b89a22b..4ffd8125422 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -683,7 +683,12 @@ public: } String* val_str(String* str); const char *func_name() const { return "inet_ntoa"; } - void fix_length_and_dec() { decimals = 0; max_length=3*8+7; } + void fix_length_and_dec() + { + decimals= 0; + max_length= 3 * 8 + 7; + maybe_null= 1; + } }; class Item_func_quote :public Item_str_func From 0b0071743299aaaba6a14da099abc9be2afd6100 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Mon, 22 Oct 2007 22:35:08 +0400 Subject: [PATCH 09/44] Fixed the Windows build failures introduced by the patch for bug #31207: Test "join_nested" shows different strategy on IA64 CPUs / Intel's ICC compiler. --- libmysql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt index 59e70d68a6d..6f5d8a49363 100755 --- a/libmysql/CMakeLists.txt +++ b/libmysql/CMakeLists.txt @@ -96,7 +96,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c ../strings/strmov.c ../strings/strnlen.c ../strings/strnmov.c ../strings/strtod.c ../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c ../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c - ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c + ../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c ${LIB_SOURCES}) # Need to set USE_TLS for building the DLL, since __declspec(thread) From c085e424f6e7289e906121051bec62433833b062 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Tue, 23 Oct 2007 06:54:31 +0200 Subject: [PATCH 10/44] Bug #20901: CREATE privilege is enough to insert into a table CREATE TABLE IF NOT EXISTS ... SELECT let you insert into an existing table as long as you had the CREATE privilege. CREATE ... SELECT variants now always require INSERT privilege on target table. --- mysql-test/r/create.result | 38 +++++++++++++++++++ mysql-test/r/grant.result | 6 +-- mysql-test/t/create.test | 76 ++++++++++++++++++++++++++++++++++++++ mysql-test/t/grant.test | 2 +- sql/sql_parse.cc | 9 ++++- 5 files changed, 126 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index aa25c55f394..17894c65109 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -701,3 +701,41 @@ t2 CREATE TABLE `t2` ( drop table t1, t2; create table t1(a set("a,b","c,d") not null); ERROR HY000: Illegal set 'a,b' value found during parsing +create database mysqltest; +use mysqltest; +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); +insert into t1 values (1); +ERROR 42000: Access denied for user 'mysqltest'@'localhost' to database 'mysqltest' +create table t2 (i INT); +create table t4 (i INT); +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; +insert into t2 values (1); +create table if not exists t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +create table if not exists t3 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't3' +create table if not exists t4 select * from t2; +Warnings: +Note 1050 Table 't4' already exists +create table if not exists t5 select * from t2; +create table t6 select * from t2; +create table t7 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't7' +create table t4 select * from t2; +ERROR 42S01: Table 't4' already exists +create table t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +drop table t1,t2,t4,t5,t6; +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +flush privileges; +drop database mysqltest; +use test; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 4e4e2ccff48..2f457a4acbc 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -349,12 +349,12 @@ show grants for grant_user@localhost; Grants for grant_user@localhost GRANT USAGE ON *.* TO 'grant_user'@'localhost' GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost' -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; Host Db User Table_name Column_name Column_priv -localhost test grant_user t1 b Insert -localhost test grant_user t1 d Insert localhost test grant_user t1 a Insert +localhost test grant_user t1 b Insert localhost test grant_user t1 c Insert +localhost test grant_user t1 d Insert revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; Grants for grant_user@localhost diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 57b16a13c01..d54615ddb4d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -609,4 +609,80 @@ drop table t1, t2; --error 1105 create table t1(a set("a,b","c,d") not null); +# +# Bug #20901 - CREATE privilege is enough to insert into a table +# + +create database mysqltest; +use mysqltest; + +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); + +connect (user1,localhost,mysqltest,,mysqltest); +connection user1; +# show we don't have INSERT +--error 1044 +insert into t1 values (1); +# show we have CREATE +create table t2 (i INT); +create table t4 (i INT); + +connection default; +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +# to specify ACLs for non-existent objects, must explictly |CREATE +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; + +connection user1; +insert into t2 values (1); + + +# CREATE IF NOT EXISTS...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table if not exists t1 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t3 yet, no INSERT, must fail +--error 1142 +create table if not exists t3 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, t4 exists, have INSERT, must succeed +create table if not exists t4 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t5 yet, have INSERT, must succeed +create table if not exists t5 select * from t2; + + +# CREATE...SELECT, no t6 yet, have INSERT, must succeed +create table t6 select * from t2; + +# CREATE...SELECT, no t7 yet, no INSERT, must fail +--error 1142 +create table t7 select * from t2; + +# CREATE...SELECT, t4 exists, have INSERT, must still fail (exists) +--error 1050 +create table t4 select * from t2; + +# CREATE...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table t1 select * from t2; + + +connection default; +drop table t1,t2,t4,t5,t6; + +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +flush privileges; + +disconnect user1; +drop database mysqltest; +use test; + # End of 4.1 tests diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index ea148c67262..dcdf3f6f4e0 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -296,7 +296,7 @@ DROP DATABASE testdb10; create table t1(a int, b int, c int, d int); grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost; show grants for grant_user@localhost; -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 24f9ef30569..880a145903c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5832,8 +5832,15 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables, int error= 1; // Error message is given DBUG_ENTER("create_table_precheck"); + /* + Require CREATE [TEMPORARY] privilege on new table; for + CREATE TABLE ... SELECT, also require INSERT. + */ + want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL); + CREATE_TMP_ACL : CREATE_ACL) | + (select_lex->item_list.elements ? INSERT_ACL : 0); + if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, 0, 0) || check_merge_table_access(thd, create_table->db, From 90f391c01388d9c556351ac622a7ef5200c16bba Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Tue, 23 Oct 2007 07:09:16 +0200 Subject: [PATCH 11/44] Bug #20901: CREATE privilege is enough to insert into a table CREATE TABLE IF NOT EXISTS ... SELECT let you insert into an existing table as long as you had the CREATE privilege. CREATE ... SELECT variants now always require INSERT privilege on target table. --- mysql-test/r/create.result | 2 +- mysql-test/t/create.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 006dc951297..daafaa1a45a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -755,7 +755,7 @@ use mysqltest; grant create on mysqltest.* to mysqltest@localhost; create table t1 (i INT); insert into t1 values (1); -ERROR 42000: Access denied for user 'mysqltest'@'localhost' to database 'mysqltest' +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' create table t2 (i INT); create table t4 (i INT); grant select, insert on mysqltest.t2 to mysqltest@localhost; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 106ecbb2586..8d76787de5a 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -667,7 +667,7 @@ create table t1 (i INT); connect (user1,localhost,mysqltest,,mysqltest); connection user1; # show we don't have INSERT ---error 1044 +--error 1142 insert into t1 values (1); # show we have CREATE create table t2 (i INT); From acd497ad71bb85f6b2901ed50f45c7782f97d1a9 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Tue, 23 Oct 2007 11:52:55 +0200 Subject: [PATCH 12/44] Bug#30560 Valgrind option to mysql-test-run with spaces in cause strange error --- mysql-test/mysql-test-run.pl | 48 +++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1ec91d200a5..b81d2eb0019 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -255,13 +255,13 @@ our $opt_timer= 1; our $opt_user; -our $opt_valgrind= 0; -our $opt_valgrind_mysqld= 0; -our $opt_valgrind_mysqltest= 0; -our $default_valgrind_options= "--show-reachable=yes"; -our $opt_valgrind_options; -our $opt_valgrind_path; -our $opt_callgrind; +my $opt_valgrind= 0; +my $opt_valgrind_mysqld= 0; +my $opt_valgrind_mysqltest= 0; +my @default_valgrind_args= ("--show-reachable=yes"); +my @valgrind_args; +my $opt_valgrind_path; +my $opt_callgrind; our $opt_stress= ""; our $opt_stress_suite= "main"; @@ -575,7 +575,18 @@ sub command_line_setup () { 'valgrind|valgrind-all' => \$opt_valgrind, 'valgrind-mysqltest' => \$opt_valgrind_mysqltest, 'valgrind-mysqld' => \$opt_valgrind_mysqld, - 'valgrind-options=s' => \$opt_valgrind_options, + 'valgrind-options=s' => sub { + my ($opt, $value)= @_; + # Deprecated option unless it's what we know pushbuild uses + if ($value eq "--gen-suppressions=all --show-reachable=yes") { + push(@valgrind_args, $_) for (split(' ', $value)); + return; + } + die("--valgrind-options=s is deprecated. Use ", + "--valgrind-option=s, to be specified several", + " times if necessary"); + }, + 'valgrind-option=s' => \@valgrind_args, 'valgrind-path=s' => \$opt_valgrind_path, 'callgrind' => \$opt_callgrind, @@ -992,7 +1003,7 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Check valgrind arguments # -------------------------------------------------------------------------- - if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) + if ( $opt_valgrind or $opt_valgrind_path or @valgrind_args) { mtr_report("Turning on valgrind for all executables"); $opt_valgrind= 1; @@ -1017,17 +1028,18 @@ sub command_line_setup () { $opt_valgrind_mysqld= 1; # Set special valgrind options unless options passed on command line - $opt_valgrind_options="--trace-children=yes" - unless defined $opt_valgrind_options; + push(@valgrind_args, "--trace-children=yes") + unless @valgrind_args; } if ( $opt_valgrind ) { # Set valgrind_options to default unless already defined - $opt_valgrind_options=$default_valgrind_options - unless defined $opt_valgrind_options; + push(@valgrind_args, @default_valgrind_args) + unless @valgrind_args; - mtr_report("Running valgrind with options \"$opt_valgrind_options\""); + mtr_report("Running valgrind with options \"", + join(" ", @valgrind_args), "\""); } if ( ! $opt_testcase_timeout ) @@ -5008,7 +5020,7 @@ sub valgrind_arguments { } # Add valgrind options, can be overriden by user - mtr_add_arg($args, '%s', $opt_valgrind_options); + mtr_add_arg($args, '%s', $_) for (@valgrind_args); mtr_add_arg($args, $$exe); @@ -5148,12 +5160,14 @@ Options for coverage, profiling etc gcov FIXME gprof FIXME valgrind Run the "mysqltest" and "mysqld" executables using - valgrind with options($default_valgrind_options) + valgrind with default options valgrind-all Synonym for --valgrind valgrind-mysqltest Run the "mysqltest" and "mysql_client_test" executable with valgrind valgrind-mysqld Run the "mysqld" executable with valgrind - valgrind-options=ARGS Options to give valgrind, replaces default options + valgrind-options=ARGS Deprecated, use --valgrind-option + valgrind-option=ARGS Option to give valgrind, replaces default option(s), + can be specified more then once valgrind-path=[EXE] Path to the valgrind executable callgrind Instruct valgrind to use callgrind From c380020a7e70a8fdfefb72f9aafa3657577ff176 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 24 Oct 2007 13:28:46 +0500 Subject: [PATCH 13/44] after-merge fix: new sys_var_character_set_client classs introduced to perform separate checking. --- sql/set_var.cc | 25 ++++++++++++++++++++++++- sql/set_var.h | 14 ++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index b6b102aa4d0..8ab91caf1f3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -164,7 +164,8 @@ static sys_var_character_set_sv sys_character_set_server(&vars, "character_set_s sys_var_const_str sys_charset_system(&vars, "character_set_system", (char *)my_charset_utf8_general_ci.name); static sys_var_character_set_database sys_character_set_database(&vars, "character_set_database"); -static sys_var_character_set_sv sys_character_set_client(&vars, "character_set_client", +static sys_var_character_set_client sys_character_set_client(&vars, + "character_set_client", &SV::character_set_client, &default_charset_info); static sys_var_character_set_sv sys_character_set_connection(&vars, "character_set_connection", @@ -1861,6 +1862,21 @@ CHARSET_INFO **sys_var_character_set_sv::ci_ptr(THD *thd, enum_var_type type) } +bool sys_var_character_set_client::check(THD *thd, set_var *var) +{ + if (sys_var_character_set_sv::check(thd, var)) + return 1; + /* Currently, UCS-2 cannot be used as a client character set */ + if (var->save_result.charset->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->save_result.charset->csname); + return 1; + } + return 0; +} + + CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type type) { @@ -2290,6 +2306,13 @@ uchar *sys_var_log_output::value_ptr(THD *thd, enum_var_type type, int set_var_collation_client::check(THD *thd) { + /* Currently, UCS-2 cannot be used as a client character set */ + if (character_set_client->mbminlen > 1) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client", + character_set_client->csname); + return 1; + } return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index eb2c893c89e..0e282212a3f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -667,6 +667,20 @@ public: }; +class sys_var_character_set_client: public sys_var_character_set_sv +{ +public: + sys_var_character_set_client(sys_var_chain *chain, const char *name_arg, + CHARSET_INFO *SV::*offset_arg, + CHARSET_INFO **global_default_arg, + bool is_nullable= 0) + : sys_var_character_set_sv(chain, name_arg, offset_arg, global_default_arg, + is_nullable) + { } + bool check(THD *thd, set_var *var); +}; + + class sys_var_character_set_database :public sys_var_character_set { public: From 78aa659979b02afeb26ec51742559e516a2ba41e Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Wed, 24 Oct 2007 21:16:20 +0400 Subject: [PATCH 14/44] Fix for bug #31566: my_write(fd, 0x0, 0, flags) fails with EFAULT on some platforms Since the behavior of write(fd, buf, 0) is undefined, it may fail with EFAULT on some architectures when buf == NULL. The error was propagated up to a caller, since my_write() code did not handle it properly. Fixed by checking the 'number of bytes' argument in my_write() and returning before calling the write() system call when there is nothing to write. --- mysys/my_write.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysys/my_write.c b/mysys/my_write.c index 4c3d187e4e8..08d70accd57 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -29,6 +29,10 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) Filedes, (long) Buffer, Count, MyFlags)); errors=0; written=0L; + /* The behavior of write(fd, buf, 0) is not portable */ + if (unlikely(!Count)) + return 0; + for (;;) { if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count) From bb79b4662f104c45edd3c61de8ff871a1d834ab1 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 24 Oct 2007 22:36:57 +0500 Subject: [PATCH 15/44] Fix for bug #30679: 5.1 name encoding not performed for views during upgrade Problem: we skip views perfoming --fix-table-names. Fix: rename views as well. --- client/mysqlcheck.c | 7 +++++-- mysql-test/r/mysqlcheck.result | 18 ++++++++++++++++++ mysql-test/t/mysqlcheck.test | 13 +++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index fb2071ce10f..34f09f6ca92 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -533,8 +533,11 @@ static int process_all_tables_in_db(char *database) else { while ((row = mysql_fetch_row(res))) - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) + /* + Skip tables with an engine of NULL (probably a view) + if we don't perform renaming. + */ + if (row[1] || what_to_do == DO_UPGRADE) { handle_request_for_tables(row[0], strlen(row[0])); } diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b8ada0adff9..ac21e0aeb6a 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -58,3 +58,21 @@ test.t1 OK drop view v1; drop table t1; End of 5.0 tests +create table t1(a int); +create view v1 as select * from t1; +show tables; +Tables_in_test +t1 +v1 +show tables; +Tables_in_test +t1 +#mysql50#v-1 +v1 +show tables; +Tables_in_test +t1 +v1 +v-1 +drop view v1, `v-1`; +drop table t1; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index d233546f9e3..b789e275ffe 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -38,3 +38,16 @@ drop view v1; drop table t1; --echo End of 5.0 tests + +# +# Bug #30679: 5.1 name encoding not performed for views during upgrade +# +create table t1(a int); +create view v1 as select * from t1; +show tables; +--copy_file $MYSQLTEST_VARDIR/master-data/test/v1.frm $MYSQLTEST_VARDIR/master-data/test/v-1.frm +show tables; +--exec $MYSQL_CHECK --check-upgrade --fix-table-names --databases test +show tables; +drop view v1, `v-1`; +drop table t1; From 3494f691c1da55fc37b2b64476ba1c03dde76100 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Thu, 25 Oct 2007 08:19:57 +0400 Subject: [PATCH 16/44] Replaced 'return' with DBUG_RETURN() in the fix for bug #31566. --- mysys/my_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_write.c b/mysys/my_write.c index 08d70accd57..9ff7babab31 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -31,7 +31,7 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) /* The behavior of write(fd, buf, 0) is not portable */ if (unlikely(!Count)) - return 0; + DBUG_RETURN(0); for (;;) { From 8ec674dd0c42714214d9b9b1a10ae214fcc77103 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Fri, 26 Oct 2007 15:37:38 +0500 Subject: [PATCH 17/44] Fix for bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0, file .\ha_innodb. Problem: if a partial unique key followed by a non-partial one we declare the second one as a primary key. Fix: sort non-partial unique keys before partial ones. --- include/my_base.h | 2 +- mysql-test/r/innodb_mysql.result | 15 +++++++++++ mysql-test/r/key.result | 44 ++++++++++++++++++++++++++++++++ mysql-test/t/innodb_mysql.test | 9 +++++++ mysql-test/t/key.test | 18 +++++++++++++ sql/sql_table.cc | 26 +++++++++++++------ sql/structs.h | 2 +- 7 files changed, 106 insertions(+), 10 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index ef5ac364fed..9240b01a9f1 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -224,7 +224,7 @@ enum ha_base_keytype { #define HA_SPATIAL 1024 /* For spatial search */ #define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */ #define HA_GENERATED_KEY 8192 /* Automaticly generated key */ - +#define HA_KEY_HAS_PART_KEY_SEG 65536 /* Key contains partial segments */ /* Automatic bits in key-flag */ #define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */ diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index d5f014b6840..5a85df76347 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1211,4 +1211,19 @@ a b 3 2 1 1 DROP TABLE t1; +create table t1(a char(10) not null, unique key aa(a(1)), +b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +Field Type Null Key Default Extra +a char(10) NO UNI NULL +b char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) NOT NULL, + `b` char(4) NOT NULL, + UNIQUE KEY `bb` (`b`), + UNIQUE KEY `aa` (`a`(1)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 2fc751c63bf..0f1ea46bd61 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -462,4 +462,48 @@ EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 DROP TABLE t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null, unique key cc(c)); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO NULL +alter table t1 add unique key cc(c); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests. diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index f64efd600c5..13aa6afd701 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -960,4 +960,13 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a char(10) not null, unique key aa(a(1)), + b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 3d0e68dc0f3..f63336a9864 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -443,4 +443,22 @@ ALTER TABLE t1 DISABLE KEYS; EXPLAIN SELECT MAX(a) FROM t1 FORCE INDEX(a); DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null, unique key cc(c)); +desc t1; +show create table t1; +drop table t1; +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null); +desc t1; +alter table t1 add unique key cc(c); +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests. diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b6e41788ef0..9d6f66aff53 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -361,7 +361,8 @@ int quick_rm_table(enum db_type base,const char *db, /* Sort keys in the following order: - PRIMARY KEY - - UNIQUE keyws where all column are NOT NULL + - UNIQUE keys where all column are NOT NULL + - UNIQUE keys that don't contain partial segments - Other UNIQUE keys - Normal keys - Fulltext keys @@ -372,26 +373,31 @@ int quick_rm_table(enum db_type base,const char *db, static int sort_keys(KEY *a, KEY *b) { - if (a->flags & HA_NOSAME) + ulong a_flags= a->flags, b_flags= b->flags; + + if (a_flags & HA_NOSAME) { - if (!(b->flags & HA_NOSAME)) + if (!(b_flags & HA_NOSAME)) return -1; - if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) { /* Sort NOT NULL keys before other keys */ - return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; } if (a->name == primary_key_name) return -1; if (b->name == primary_key_name) return 1; + /* Sort keys don't containing partial segments before others */ + if ((a_flags ^ b_flags) & HA_KEY_HAS_PART_KEY_SEG) + return (a_flags & HA_KEY_HAS_PART_KEY_SEG) ? 1 : -1; } - else if (b->flags & HA_NOSAME) + else if (b_flags & HA_NOSAME) return 1; // Prefer b - if ((a->flags ^ b->flags) & HA_FULLTEXT) + if ((a_flags ^ b_flags) & HA_FULLTEXT) { - return (a->flags & HA_FULLTEXT) ? 1 : -1; + return (a_flags & HA_FULLTEXT) ? 1 : -1; } /* Prefer original key order. usable_key_parts contains here @@ -1421,6 +1427,10 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, else key_info->flags|= HA_PACK_KEY; } + /* Check if the key segment is partial, set the key flag accordingly */ + if (length != sql_field->key_length) + key_info->flags|= HA_KEY_HAS_PART_KEY_SEG; + key_length+=length; key_part_info++; diff --git a/sql/structs.h b/sql/structs.h index 28bdd8c1519..bc373fe4b52 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -87,7 +87,7 @@ typedef struct st_key_part_info { /* Info about a key part */ typedef struct st_key { uint key_length; /* Tot length of key */ - uint flags; /* dupp key and pack flags */ + ulong flags; /* dupp key and pack flags */ uint key_parts; /* How many key_parts */ uint extra_length; uint usable_key_parts; /* Should normally be = key_parts */ From 98a4d99961eae8c3a224739099fc95544ff2b43d Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Mon, 29 Oct 2007 12:20:21 +0400 Subject: [PATCH 18/44] Fix for bug #30782: Truncated UNSIGNED BIGINT columns only in SELECT w/ CASE, JOIN, and ORDER BY Problem: improper maximum length calculation of the CASE function leads to decimal value truncation (storing/retrieving decimal field values). Fix: accurately calculate maximum length/unsigned flag/decimals parameters of the CASE function. --- mysql-test/r/case.result | 20 +++++++++++++++++++- mysql-test/t/case.test | 21 +++++++++++++++++++-- sql/item_cmpfunc.cc | 36 ++++++++++++++++++++++++++++++------ sql/item_cmpfunc.h | 2 ++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index cf358e6a404..bc05edcfac1 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1, t2; select CASE "b" when "a" then 1 when "b" then 2 END; CASE "b" when "a" then 1 when "b" then 2 END 2 @@ -200,3 +200,21 @@ CEMPNUM EMPMUM1 EMPNUM2 0.00 0 0.00 2.00 2 NULL DROP TABLE t1,t2; +End of 4.1 tests +create table t1 (a int, b bigint unsigned); +create table t2 (c int); +insert into t1 (a, b) values (1,4572794622775114594), (2,18196094287899841997), +(3,11120436154190595086); +insert into t2 (c) values (1), (2), (3); +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 +join t2 on t1.a=t2.c order by d; +a d +1 4572794622775114594 +3 11120436154190595086 +2 18196094287899841997 +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 +join t2 on t1.a=t2.c where b=11120436154190595086 order by d; +a d +3 11120436154190595086 +drop table t1, t2; +End of 5.0 tests diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 0e9e141f6d8..b6654df4ecb 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1; +drop table if exists t1, t2; --enable_warnings select CASE "b" when "a" then 1 when "b" then 2 END; @@ -152,4 +152,21 @@ SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; DROP TABLE t1,t2; -# End of 4.1 tests + +--echo End of 4.1 tests + +# +# #30782: Truncated UNSIGNED BIGINT columns +# +create table t1 (a int, b bigint unsigned); +create table t2 (c int); +insert into t1 (a, b) values (1,4572794622775114594), (2,18196094287899841997), + (3,11120436154190595086); +insert into t2 (c) values (1), (2), (3); +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 + join t2 on t1.a=t2.c order by d; +select t1.a, (case t1.a when 0 then 0 else t1.b end) d from t1 + join t2 on t1.a=t2.c where b=11120436154190595086 order by d; +drop table t1, t2; + +--echo End of 5.0 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..8cbbc115922 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2530,6 +2530,23 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref) } +void Item_func_case::agg_str_lengths(Item* arg) +{ + set_if_bigger(max_length, arg->max_length); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + + +void Item_func_case::agg_num_lengths(Item *arg) +{ + uint len= my_decimal_length_to_precision(arg->max_length, arg->decimals, + arg->unsigned_flag) - arg->decimals; + set_if_bigger(max_length, len); + set_if_bigger(decimals, arg->decimals); + unsigned_flag= unsigned_flag && arg->unsigned_flag; +} + void Item_func_case::fix_length_and_dec() { @@ -2579,15 +2596,22 @@ void Item_func_case::fix_length_and_dec() max_length=0; decimals=0; - for (uint i=0 ; i < ncases ; i+=2) + unsigned_flag= TRUE; + if (cached_result_type == STRING_RESULT) { - set_if_bigger(max_length,args[i+1]->max_length); - set_if_bigger(decimals,args[i+1]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_str_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_str_lengths(args[else_expr_num]); } - if (else_expr_num != -1) + else { - set_if_bigger(max_length,args[else_expr_num]->max_length); - set_if_bigger(decimals,args[else_expr_num]->decimals); + for (uint i= 0; i < ncases; i+= 2) + agg_num_lengths(args[i + 1]); + if (else_expr_num != -1) + agg_num_lengths(args[else_expr_num]); + max_length= my_decimal_precision_to_length(max_length + decimals, decimals, + unsigned_flag); } } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..3e32b5d2c9c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -753,6 +753,8 @@ public: void print(String *str); Item *find_item(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + void agg_str_lengths(Item *arg); + void agg_num_lengths(Item *arg); }; From 9d57de144fc58ca230801b517300a39a98c3fcd1 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Mon, 29 Oct 2007 20:31:03 +0400 Subject: [PATCH 19/44] after-merge fix-up. --- mysql-test/include/mix1.inc | 9 +++++++ mysql-test/r/innodb_mysql.result | 15 +++++++++++ mysql-test/r/key.result | 45 ++++++++++++++++++++++++++++++++ mysql-test/t/key.test | 20 ++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index aee5613ff35..4d910e86e0f 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1019,6 +1019,15 @@ SELECT * FROM t1 ORDER BY b DESC, a ASC; DROP TABLE t1; +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a char(10) not null, unique key aa(a(1)), + b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +show create table t1; +drop table t1; + --echo End of 5.0 tests # Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3a6758b38f4..8f46df311ad 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -1287,6 +1287,21 @@ a b 3 2 1 1 DROP TABLE t1; +create table t1(a char(10) not null, unique key aa(a(1)), +b char(4) not null, unique key bb(b(4))) engine=innodb; +desc t1; +Field Type Null Key Default Extra +a char(10) NO UNI NULL +b char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) NOT NULL, + `b` char(4) NOT NULL, + UNIQUE KEY `bb` (`b`), + UNIQUE KEY `aa` (`a`(1)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t1; End of 5.0 tests CREATE TABLE `t2` ( `k` int(11) NOT NULL auto_increment, diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index a2bed75a709..a3e63a0bdf4 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -530,3 +530,48 @@ ORDER BY c.b, c.d a b c d e f g h i j a b c d 2 2 1 2004-11-30 12:00:00 1 0 0 0 0 0 2 3388000 -553000 NULL DROP TABLE t1, t2; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null, unique key cc(c)); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1(a int not null, key aa(a), +b char(10) not null, unique key bb(b(1)), +c char(4) not null); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO NULL +alter table t1 add unique key cc(c); +desc t1; +Field Type Null Key Default Extra +a int(11) NO MUL NULL +b char(10) NO UNI NULL +c char(4) NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` char(10) NOT NULL, + `c` char(4) NOT NULL, + UNIQUE KEY `cc` (`c`), + UNIQUE KEY `bb` (`b`(1)), + KEY `aa` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index f1eb8e68b49..f4d99024206 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -501,3 +501,23 @@ ORDER BY c.b, c.d ; DROP TABLE t1, t2; + +# +# Bug #31137: Assertion failed: primary_key_no == -1 || primary_key_no == 0 +# +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null, unique key cc(c)); +desc t1; +show create table t1; +drop table t1; +create table t1(a int not null, key aa(a), + b char(10) not null, unique key bb(b(1)), + c char(4) not null); +desc t1; +alter table t1 add unique key cc(c); +desc t1; +show create table t1; +drop table t1; + +--echo End of 5.0 tests From 38b3b367545e34c7759fa8ee45c78e85765706b0 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Tue, 30 Oct 2007 12:51:57 +0400 Subject: [PATCH 20/44] Fix for bug #30654: mysqlcheck fails during upgrade of tables whose names include backticks or blank Problem: mysqlcheck doesn't escape backtick characters in the table names. Fix: escape them. --- client/mysqlcheck.c | 52 +++++++++++++++++++++++++--------- mysql-test/r/mysqlcheck.result | 7 ++++- mysql-test/t/mysqlcheck.test | 11 ++++++- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 8205a83fdf4..3b504eb50b0 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -186,6 +186,7 @@ static void dbDisconnect(char *host); static void DBerror(MYSQL *mysql, const char *when); static void safe_exit(int error); static void print_result(); +static uint fixed_name_length(const char *name); static char *fix_table_name(char *dest, char *src); int what_to_do = 0; @@ -409,14 +410,14 @@ static int process_selected_tables(char *db, char **table_names, int tables) { /* We need table list in form `a`, `b`, `c` - that's why we need 4 more chars added to to each table name + that's why we need 2 more chars added to to each table name space is for more readable output in logs and in case of error */ char *table_names_comma_sep, *end; int i, tot_length = 0; for (i = 0; i < tables; i++) - tot_length += strlen(*(table_names + i)) + 4; + tot_length+= fixed_name_length(*(table_names + i)) + 2; if (!(table_names_comma_sep = (char *) my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME)))) @@ -434,23 +435,46 @@ static int process_selected_tables(char *db, char **table_names, int tables) } else for (; tables > 0; tables--, table_names++) - handle_request_for_tables(*table_names, strlen(*table_names)); + handle_request_for_tables(*table_names, fixed_name_length(*table_names)); return 0; } /* process_selected_tables */ +static uint fixed_name_length(const char *name) +{ + const char *p; + uint extra_length= 2; /* count the first/last backticks */ + + for (p= name; *p; p++) + { + if (*p == '`') + extra_length++; + else if (*p == '.') + extra_length+= 2; + } + return (p - name) + extra_length; +} + + static char *fix_table_name(char *dest, char *src) { - char *db_sep; - *dest++= '`'; - if ((db_sep= strchr(src, '.'))) + for (; *src; src++) { - dest= strmake(dest, src, (uint) (db_sep - src)); - dest= strmov(dest, "`.`"); - src= db_sep + 1; + switch (*src) { + case '.': /* add backticks around '.' */ + *dest++= '`'; + *dest++= '.'; + *dest++= '`'; + break; + case '`': /* escape backtick character */ + *dest++= '`'; + /* fall through */ + default: + *dest++= *src; + } } - dest= strxmov(dest, src, "`", NullS); + *dest++= '`'; return dest; } @@ -471,7 +495,7 @@ static int process_all_tables_in_db(char *database) { /* We need table list in form `a`, `b`, `c` - that's why we need 4 more chars added to to each table name + that's why we need 2 more chars added to to each table name space is for more readable output in logs and in case of error */ @@ -479,7 +503,7 @@ static int process_all_tables_in_db(char *database) uint tot_length = 0; while ((row = mysql_fetch_row(res))) - tot_length += strlen(row[0]) + 4; + tot_length+= fixed_name_length(row[0]) + 2; mysql_data_seek(res, 0); if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME)))) @@ -507,7 +531,7 @@ static int process_all_tables_in_db(char *database) /* Skip tables with an engine of NULL (probably a view). */ if (row[1]) { - handle_request_for_tables(row[0], strlen(row[0])); + handle_request_for_tables(row[0], fixed_name_length(row[0])); } } mysql_free_result(res); @@ -741,7 +765,7 @@ int main(int argc, char **argv) for (i = 0; i < tables4repair.elements ; i++) { char *name= (char*) dynamic_array_ptr(&tables4repair, i); - handle_request_for_tables(name, strlen(name)); + handle_request_for_tables(name, fixed_name_length(name)); } } end: diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index b2820df8f4c..f8a28009c42 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, `t``1`, `t 1`; drop view if exists v1; drop database if exists client_test_db; mysql.columns_priv OK @@ -41,4 +41,9 @@ test.t1 OK test.t1 OK drop view v1; drop table t1; +create table `t``1`(a int); +create table `t 1`(a int); +test.t 1 OK +test.t`1 OK +drop table `t``1`, `t 1`; End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index f4e18d4004f..04e7b6b4bdb 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -2,7 +2,7 @@ # --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, `t``1`, `t 1`; drop view if exists v1; drop database if exists client_test_db; --enable_warnings @@ -31,4 +31,13 @@ create view v1 as select * from t1; drop view v1; drop table t1; +# +# Bug #30654: mysqlcheck fails during upgrade of tables whose names include backticks +# +create table `t``1`(a int); +create table `t 1`(a int); +--replace_result 'Table is already up to date' OK +--exec $MYSQL_CHECK --databases test +drop table `t``1`, `t 1`; + --echo End of 5.0 tests From 5dc5fc82923e32dfd4a112c696810d77619e02e5 Mon Sep 17 00:00:00 2001 From: "knielsen@loke.(none)" <> Date: Wed, 31 Oct 2007 10:34:26 +0100 Subject: [PATCH 21/44] BUG#31799: Scrambled number output due to integer overflow An integer overflow in number->string conversion caused completely wrong output of the number LONGLONG_MIN with gcc 4.2.1. Fixed by eliminating the overflow, using only operations that are well-defined in ANSI C. --- strings/ctype-simple.c | 24 ++++++++++++++---------- strings/ctype-ucs2.c | 24 ++++++++++++++---------- strings/int2str.c | 16 ++++++++++------ strings/longlong2str.c | 32 ++++++++++++++++++-------------- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index e073262cd4c..99e02e02014 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -837,6 +837,7 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), register char *p, *e; long int new_val; uint sign=0; + unsigned long int uval = (unsigned long int) val; e = p = &buffer[sizeof(buffer)-1]; *p= 0; @@ -845,15 +846,16 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val= -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval= (unsigned long int)0 - uval; *dst++= '-'; len--; sign= 1; } } - new_val = (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val = (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) @@ -876,12 +878,14 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), register char *p, *e; long long_val; uint sign= 0; + ulonglong uval = (ulonglong)val; if (radix < 0) { if (val < 0) { - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; *dst++= '-'; len--; sign= 1; @@ -891,22 +895,22 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), e = p = &buffer[sizeof(buffer)-1]; *p= 0; - if (val == 0) + if (uval == 0) { *--p= '0'; len= 1; goto cnv; } - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = '0' + rem; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index b5353c55e4c..97e5defdec1 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1018,6 +1018,7 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, register char *p, *db, *de; long int new_val; int sl=0; + unsigned long int uval = (unsigned long int) val; p = &buffer[sizeof(buffer)-1]; *p='\0'; @@ -1027,12 +1028,13 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, if (val < 0) { sl = 1; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (unsigned long int)0 - uval; } } - new_val = (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val = (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) @@ -1065,34 +1067,36 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)), register char *p, *db, *de; long long_val; int sl=0; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (val < 0) { sl=1; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } } p = &buffer[sizeof(buffer)-1]; *p='\0'; - if (val == 0) + if (uval == 0) { *--p='0'; goto cnv; } - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = '0' + rem; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; diff --git a/strings/int2str.c b/strings/int2str.c index 9fc53032819..fba98aac3f1 100644 --- a/strings/int2str.c +++ b/strings/int2str.c @@ -57,6 +57,7 @@ int2str(register long int val, register char *dst, register int radix, register char *p; long int new_val; char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower; + ulong uval= (ulong) val; if (radix < 0) { @@ -65,7 +66,8 @@ int2str(register long int val, register char *dst, register int radix, if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulong)0 - uval; } radix = -radix; } @@ -86,8 +88,8 @@ int2str(register long int val, register char *dst, register int radix, */ p = &buffer[sizeof(buffer)-1]; *p = '\0'; - new_val=(ulong) val / (ulong) radix; - *--p = dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)]; + new_val= uval / (ulong) radix; + *--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)]; val = new_val; #ifdef HAVE_LDIV while (val != 0) @@ -133,20 +135,22 @@ char *int10_to_str(long int val,char *dst,int radix) char buffer[65]; register char *p; long int new_val; + unsigned long int uval = (unsigned long int) val; if (radix < 0) /* -10 */ { if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (unsigned long int)0 - uval; } } p = &buffer[sizeof(buffer)-1]; *p = '\0'; - new_val= (long) ((unsigned long int) val / 10); - *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); + new_val= (long) (uval / 10); + *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); val = new_val; while (val != 0) diff --git a/strings/longlong2str.c b/strings/longlong2str.c index c464abcfccd..d7de5bb0f7c 100644 --- a/strings/longlong2str.c +++ b/strings/longlong2str.c @@ -51,13 +51,15 @@ char *longlong2str(longlong val,char *dst,int radix) char buffer[65]; register char *p; long long_val; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (radix < -36 || radix > -2) return (char*) 0; if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } radix = -radix; } @@ -65,7 +67,7 @@ char *longlong2str(longlong val,char *dst,int radix) { if (radix > 36 || radix < 2) return (char*) 0; } - if (val == 0) + if (uval == 0) { *dst++='0'; *dst='\0'; @@ -74,14 +76,14 @@ char *longlong2str(longlong val,char *dst,int radix) p = &buffer[sizeof(buffer)-1]; *p = '\0'; - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) radix; - uint rem= (uint) (val- quo* (uint) radix); + ulonglong quo= uval/(uint) radix; + uint rem= (uint) (uval- quo* (uint) radix); *--p = _dig_vec_upper[rem]; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/radix; @@ -100,17 +102,19 @@ char *longlong10_to_str(longlong val,char *dst,int radix) char buffer[65]; register char *p; long long_val; + ulonglong uval= (ulonglong) val; if (radix < 0) { if (val < 0) { *dst++ = '-'; - val = -val; + /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ + uval = (ulonglong)0 - uval; } } - if (val == 0) + if (uval == 0) { *dst++='0'; *dst='\0'; @@ -119,14 +123,14 @@ char *longlong10_to_str(longlong val,char *dst,int radix) p = &buffer[sizeof(buffer)-1]; *p = '\0'; - while ((ulonglong) val > (ulonglong) LONG_MAX) + while (uval > (ulonglong) LONG_MAX) { - ulonglong quo=(ulonglong) val/(uint) 10; - uint rem= (uint) (val- quo* (uint) 10); + ulonglong quo= uval/(uint) 10; + uint rem= (uint) (uval- quo* (uint) 10); *--p = _dig_vec_upper[rem]; - val= quo; + uval= quo; } - long_val= (long) val; + long_val= (long) uval; while (long_val != 0) { long quo= long_val/10; From ec5ee6f5e4bdf7c698924469bc0dca30d367401c Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:01:05 +0100 Subject: [PATCH 22/44] Fix comment --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index eae3b05f61a..e5ae9e80a88 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2675,7 +2675,7 @@ void do_copy_file(struct st_command *command) command command handle DESCRIPTION - chmod_file + chmod Change file permission of */ From 441bb13e0d46222b05a4310cab3490c7f0e3a1be Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:02:28 +0100 Subject: [PATCH 23/44] Bug#27753 enable mysql-test-run.pl to ignore tests based on wildcard - Fix problem in first implementation --- mysql-test/lib/mtr_cases.pl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 5aabb7f8863..b9943fb6cfa 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -32,16 +32,14 @@ my $skip_test; sub init_pattern { my ($from, $what)= @_; - if ( $from =~ /[a-z0-9]/ ) { + if ( $from =~ /^[a-z0-9]$/ ) { # Does not contain any regex, make the pattern match # beginning of string $from= "^$from"; } - else { - # Check that pattern is a valid regex - eval { "" =~/$from/; 1 } or - mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@"); - } + # Check that pattern is a valid regex + eval { "" =~/$from/; 1 } or + mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@"); return $from; } From 39c22a5be02d328a63a5689fb00d948ee1f5b0c0 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 11:33:35 +0100 Subject: [PATCH 24/44] Bug#32023 ndb_mgmd is slow to repsond when no nodes are up --- mysql-test/r/bdb_notembedded.result | 35 -------------------------- mysql-test/t/bdb_notembedded.test | 38 ----------------------------- ndb/src/mgmsrv/Services.cpp | 2 +- ndb/src/ndbapi/ClusterMgr.cpp | 5 +++- 4 files changed, 5 insertions(+), 75 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index b7ff4df7012..31218df019b 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -923,7 +923,6 @@ printNodeStatus(OutputStream *output, MgmtSrvr &mgmsrv, enum ndb_mgm_node_type type) { NodeId nodeId = 0; - mgmsrv.updateStatus(); while(mgmsrv.getNextNodeId(&nodeId, type)) { enum ndb_mgm_node_status status; Uint32 startPhase = 0, @@ -972,6 +971,7 @@ MgmApiSession::getStatus(Parser::Context &, m_output->println("node status"); m_output->println("nodes: %d", noOfNodes); + m_mgmsrv.updateStatus(); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_NDB); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_MGM); printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_API); diff --git a/ndb/src/ndbapi/ClusterMgr.cpp b/ndb/src/ndbapi/ClusterMgr.cpp index d3946dddfb7..a8fcb756cdf 100644 --- a/ndb/src/ndbapi/ClusterMgr.cpp +++ b/ndb/src/ndbapi/ClusterMgr.cpp @@ -222,7 +222,10 @@ ClusterMgr::forceHB() theFacade.sendSignalUnCond(&signal, nodeId); } - NdbCondition_WaitTimeout(waitForHBCond, theFacade.theMutexPtr, 1000); + /* Wait for nodes to reply - if any heartbeats was sent */ + if (!waitForHBFromNodes.isclear()) + NdbCondition_WaitTimeout(waitForHBCond, theFacade.theMutexPtr, 1000); + waitingForHB= false; #ifdef DEBUG_REG ndbout << "Still waiting for HB from " << waitForHBFromNodes.getText(buf) << endl; From f6ffb2cf8ce71a25717896d35158a8094cb85238 Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Thu, 1 Nov 2007 19:40:27 +0100 Subject: [PATCH 25/44] Bug#30630 mysql-test-run all tests fail with MySQL 5.0.41 & 5.0.45 on Mac OS X Server 10.5 --- mysql-test/mysql-test-run.pl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index b81d2eb0019..b123c377ce7 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3727,6 +3727,16 @@ sub mysqld_arguments ($$$$) { # see BUG#28359 mtr_add_arg($args, "%s--connect-timeout=60", $prefix); + + # When mysqld is run by a root user(euid is 0), it will fail + # to start unless we specify what user to run as. If not running + # as root it will be ignored, see BUG#30630 + my $euid= $>; + if (!$glob_win32 and $euid == 0 and + grep(/^--user/, @$extra_opt, @opt_extra_mysqld_opt) == 0) { + mtr_add_arg($args, "%s--user=root"); + } + if ( $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); From 173c2bb0b9f21cefe7505b1b4e8d8c35549f6fe4 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 7 Nov 2007 12:47:19 +0400 Subject: [PATCH 26/44] Fix for bug #32137: prepared statement crash with str_to_date in update clause Problem: calling non-constant argument's val_xxx() methods in the ::fix_length_and_dec() is inadmissible. Fix: call the method only for constant arguments. --- mysql-test/r/ps.result | 5 +++++ mysql-test/t/ps.test | 9 ++++++++ sql/item_timefunc.cc | 49 ++++++++++++++++++++++-------------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 49e4bf2f318..49643dd3f78 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1109,4 +1109,9 @@ a 13 DEALLOCATE PREPARE st1; DROP TABLE t1; +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; End of 4.1 tests. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 5e5dcc36b19..18beb357d05 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1146,4 +1146,13 @@ EXECUTE st1; DEALLOCATE PREPARE st1; DROP TABLE t1; +# +# Bug #32137: prepared statement crash with str_to_date in update clause +# +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; + --echo End of 4.1 tests. diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4bd3d68b9c1..08e0a727544 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2958,39 +2958,42 @@ Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg) void Item_func_str_to_date::fix_length_and_dec() { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin); - String *format; maybe_null= 1; decimals=0; cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - format= args[1]->val_str(&format_str); - if (!args[1]->null_value && (const_item= args[1]->const_item())) + if ((const_item= args[1]->const_item())) { - cached_format_type= get_date_time_result_type(format->ptr(), - format->length()); - switch (cached_format_type) { - case DATE_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_DATE; - cached_field_type= MYSQL_TYPE_DATE; - max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - case TIME_ONLY: - case TIME_MICROSECOND: - cached_timestamp_type= MYSQL_TIMESTAMP_TIME; - cached_field_type= MYSQL_TYPE_TIME; - max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - default: - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - cached_field_type= MYSQL_TYPE_DATETIME; - break; + char format_buff[64]; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + String *format= args[1]->val_str(&format_str); + if (!args[1]->null_value) + { + cached_format_type= get_date_time_result_type(format->ptr(), + format->length()); + switch (cached_format_type) { + case DATE_ONLY: + cached_timestamp_type= MYSQL_TIMESTAMP_DATE; + cached_field_type= MYSQL_TYPE_DATE; + max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + case TIME_ONLY: + case TIME_MICROSECOND: + cached_timestamp_type= MYSQL_TIMESTAMP_TIME; + cached_field_type= MYSQL_TYPE_TIME; + max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + default: + cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; + cached_field_type= MYSQL_TYPE_DATETIME; + break; + } } } } + bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) { DATE_TIME_FORMAT date_time_format; From dc8d3d0becd35419a9581f3e0195f19052e13546 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Wed, 7 Nov 2007 19:59:58 +0400 Subject: [PATCH 27/44] Fix for bug #26447: "ALTER TABLE .. ORDER" does not work with InnoDB and auto_increment keys Problems: 1. ALTER TABLE ... ORDER BY... doesn't make sence if there's a user-defined clustered index in the table. 2. using a secondary index is slower than using a clustered one for a table scan. Fixes: 1. raise a warning. 2. use the clustered index. --- mysql-test/include/mix1.inc | 8 +++++ mysql-test/r/innodb.result | 30 +++++++++--------- mysql-test/r/innodb_mysql.result | 21 ++++++++----- mysql-test/r/join_outer_innodb.result | 4 +-- sql/sql_select.cc | 10 +++++- sql/sql_table.cc | 44 +++++++++++++++++---------- 6 files changed, 75 insertions(+), 42 deletions(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 4d910e86e0f..2887a1ac40a 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -1189,4 +1189,12 @@ if ($test_foreign_keys) DROP TABLE t1; } +# +# Bug #26447: "ALTER TABLE .. ORDER" does not work with InnoDB and +# auto_increment keys +# +create table t1 (a int auto_increment primary key) engine=innodb; +alter table t1 order by a; +drop table t1; + --echo End of 5.1 tests diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..086bd714078 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -962,7 +962,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL b 4 NULL # Using index explain select a,b from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL # Using index +1 SIMPLE t1 index NULL PRIMARY 4 NULL # explain select a,b,c from t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL # @@ -1177,14 +1177,14 @@ UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000; SELECT * from t1; a b 1 1 -102 2 -103 3 4 4 5 5 6 6 7 7 8 8 9 9 +102 2 +103 3 drop table t1; CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; @@ -1208,7 +1208,6 @@ a b update t1,t2 set t1.a=t1.a+100 where t1.a=101; select * from t1; a b -201 1 102 2 103 3 104 4 @@ -1220,10 +1219,11 @@ a b 110 10 111 11 112 12 +201 1 update t1,t2 set t1.b=t1.b+10 where t1.b=2; select * from t1; a b -201 1 +102 12 103 3 104 4 105 5 @@ -1233,34 +1233,34 @@ a b 109 9 110 10 111 11 -102 12 112 12 +201 1 update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; select * from t1; a b -201 1 +102 12 103 5 104 6 -106 6 105 7 +106 6 107 7 108 8 109 9 110 10 111 11 -102 12 112 12 +201 1 select * from t2; a b 1 1 2 2 +3 13 +4 14 +5 15 6 6 7 7 8 8 9 9 -3 13 -4 14 -5 15 drop table t1,t2; CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; @@ -1311,11 +1311,11 @@ insert into t1 (id) values (null),(null),(null),(null),(null); update t1 set fk=69 where fk is null order by id limit 1; SELECT * from t1; id fk +1 69 2 NULL 3 NULL 4 NULL 5 NULL -1 69 drop table t1; create table t1 (a int not null, b int not null, key (a)); insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); @@ -2444,8 +2444,8 @@ insert into t1 (b) values (1); replace into t1 (b) values (2), (1), (3); select * from t1; a b -3 1 2 2 +3 1 4 3 truncate table t1; insert into t1 (b) values (1); @@ -2454,8 +2454,8 @@ replace into t1 (b) values (1); replace into t1 (b) values (3); select * from t1; a b -3 1 2 2 +3 1 4 3 drop table t1; create table t1 (rowid int not null auto_increment, val int not null,primary diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 8f46df311ad..775151db9f0 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -352,13 +352,13 @@ EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index +1 SIMPLE t1 index PRIMARY,name PRIMARY 4 NULL 3 Using where 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index +1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where DROP TABLE t1,t2; CREATE TABLE t1 ( @@ -1260,11 +1260,11 @@ select_type SIMPLE table t1 type index possible_keys NULL -key b -key_len 5 +key PRIMARY +key_len 4 ref NULL rows 3 -Extra Using index; Using filesort +Extra Using filesort SELECT * FROM t1 ORDER BY b ASC, a DESC; a b 1 1 @@ -1276,11 +1276,11 @@ select_type SIMPLE table t1 type index possible_keys NULL -key b -key_len 5 +key PRIMARY +key_len 4 ref NULL rows 3 -Extra Using index; Using filesort +Extra Using filesort SELECT * FROM t1 ORDER BY b DESC, a ASC; a b 2 2 @@ -1470,4 +1470,9 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2; DROP TABLE t1; +create table t1 (a int auto_increment primary key) engine=innodb; +alter table t1 order by a; +Warnings: +Warning 1105 ORDER BY ignored as there is a user-defined clustered index in the table 't1' +drop table t1; End of 5.1 tests diff --git a/mysql-test/r/join_outer_innodb.result b/mysql-test/r/join_outer_innodb.result index e8a2d6f668b..24a11b12b03 100644 --- a/mysql-test/r/join_outer_innodb.result +++ b/mysql-test/r/join_outer_innodb.result @@ -8,12 +8,12 @@ EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index +1 SIMPLE t1 index PRIMARY,name PRIMARY 4 NULL 3 Using where 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL fkey 5 NULL 5 Using index +1 SIMPLE t2 index NULL PRIMARY 4 NULL 5 1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.fkey 1 Using where DROP TABLE t1,t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1c8ff12eb92..2e28663e383 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6436,7 +6436,15 @@ make_join_readinfo(JOIN *join, ulonglong options) else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree - tab->index=find_shortest_key(table, & table->covering_keys); + /* + See bug #26447: "Using the clustered index for a table scan + is always faster than using a secondary index". + */ + if (table->s->primary_key != MAX_KEY && + table->file->primary_key_is_clustered()) + tab->index= table->s->primary_key; + else + tab->index=find_shortest_key(table, & table->covering_keys); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e6d84d0ef45..d63a6d7d3fc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6813,23 +6813,35 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (order) { - from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); - bzero((char*) &tables,sizeof(tables)); - tables.table= from; - tables.alias= tables.table_name= from->s->table_name.str; - tables.db= from->s->db.str; - error=1; + if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered()) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), + "ORDER BY ignored as there is a user-defined clustered index" + " in the table '%-.192s'", from->s->table_name.str); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + warn_buff); + } + else + { + from->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + MYF(MY_FAE | MY_ZEROFILL)); + bzero((char *) &tables, sizeof(tables)); + tables.table= from; + tables.alias= tables.table_name= from->s->table_name.str; + tables.db= from->s->db.str; + error= 1; - if (thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, - &tables, fields, all_fields, order) || - !(sortorder=make_unireg_sortorder(order, &length, NULL)) || - (from->sort.found_records = filesort(thd, from, sortorder, length, - (SQL_SELECT *) 0, HA_POS_ERROR, 1, - &examined_rows)) == - HA_POS_ERROR) - goto err; + if (thd->lex->select_lex.setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->select_lex.ref_pointer_array, + &tables, fields, all_fields, order) || + !(sortorder= make_unireg_sortorder(order, &length, NULL)) || + (from->sort.found_records= filesort(thd, from, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, + 1, &examined_rows)) == + HA_POS_ERROR) + goto err; + } }; /* Tell handler that we have values for all columns in the to table */ From 04ed1811e30c40b249b8b3bfa60cc3b684a21d5c Mon Sep 17 00:00:00 2001 From: "msvensson@pilot.mysql.com" <> Date: Fri, 9 Nov 2007 11:16:47 +0100 Subject: [PATCH 28/44] Bug#32217 rpl_ssl fails with different number of records on master and slave - Add debug queries --- mysql-test/suite/rpl/t/rpl_ssl.test | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/suite/rpl/t/rpl_ssl.test b/mysql-test/suite/rpl/t/rpl_ssl.test index c1b7bc2097b..59f0bf6a6f8 100644 --- a/mysql-test/suite/rpl/t/rpl_ssl.test +++ b/mysql-test/suite/rpl/t/rpl_ssl.test @@ -76,6 +76,16 @@ if (`select $slave_count != $master_count`) echo master and slave differed in number of rows; echo master: $master_count; echo slave: $slave_count; + + connection master; + echo === master ===; + select count(*) t1; + select * from t1; + connection slave; + echo === slave ===; + select count(*) t1; + select * from t1; + query_vertical show slave status; } connection master; From f3813c920e6820e339d15987febd8746b483bf5e Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Sat, 10 Nov 2007 18:27:57 +0400 Subject: [PATCH 29/44] manual merge. --- mysql-test/r/ps.result | 5 +++++ mysql-test/t/ps.test | 10 +++++++++ sql/item_timefunc.cc | 48 +++++++++++++++++++++++------------------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 4db588e5cac..0682cae5c80 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1136,6 +1136,11 @@ a 13 DEALLOCATE PREPARE st1; DROP TABLE t1; +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; End of 4.1 tests. create table t1 (a varchar(20)); insert into t1 values ('foo'); diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index cd2fc44e3ce..c1505ffd645 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1210,6 +1210,16 @@ EXECUTE st1; DEALLOCATE PREPARE st1; DROP TABLE t1; + +# +# Bug #32137: prepared statement crash with str_to_date in update clause +# +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; + --echo End of 4.1 tests. ############################# 5.0 tests start ################################ diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ae18e4786d7..3a2df5125ba 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -3306,38 +3306,42 @@ Field *Item_func_str_to_date::tmp_table_field(TABLE *t_arg) void Item_func_str_to_date::fix_length_and_dec() { - char format_buff[64]; - String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; maybe_null= 1; decimals=0; cached_field_type= MYSQL_TYPE_STRING; max_length= MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; cached_timestamp_type= MYSQL_TIMESTAMP_NONE; - format= args[1]->val_str(&format_str); - if (!args[1]->null_value && (const_item= args[1]->const_item())) + if ((const_item= args[1]->const_item())) { - cached_format_type= get_date_time_result_type(format->ptr(), - format->length()); - switch (cached_format_type) { - case DATE_ONLY: - cached_timestamp_type= MYSQL_TIMESTAMP_DATE; - cached_field_type= MYSQL_TYPE_DATE; - max_length= MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - case TIME_ONLY: - case TIME_MICROSECOND: - cached_timestamp_type= MYSQL_TIMESTAMP_TIME; - cached_field_type= MYSQL_TYPE_TIME; - max_length= MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - break; - default: - cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; - cached_field_type= MYSQL_TYPE_DATETIME; - break; + char format_buff[64]; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin); + String *format= args[1]->val_str(&format_str); + if (!args[1]->null_value) + { + cached_format_type= get_date_time_result_type(format->ptr(), + format->length()); + switch (cached_format_type) { + case DATE_ONLY: + cached_timestamp_type= MYSQL_TIMESTAMP_DATE; + cached_field_type= MYSQL_TYPE_DATE; + max_length= MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + case TIME_ONLY: + case TIME_MICROSECOND: + cached_timestamp_type= MYSQL_TIMESTAMP_TIME; + cached_field_type= MYSQL_TYPE_TIME; + max_length= MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN; + break; + default: + cached_timestamp_type= MYSQL_TIMESTAMP_DATETIME; + cached_field_type= MYSQL_TYPE_DATETIME; + break; + } } } } + bool Item_func_str_to_date::get_date(MYSQL_TIME *ltime, uint fuzzy_date) { DATE_TIME_FORMAT date_time_format; From 2691d9b1a98bd3329a3501cf84d8263c64c2be07 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Sat, 10 Nov 2007 18:57:09 +0400 Subject: [PATCH 30/44] manual merge. --- mysql-test/r/ps.result | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index edac68a88d6..14dec382244 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1143,6 +1143,11 @@ a 13 DEALLOCATE PREPARE st1; DROP TABLE t1; +create table t1 (a int, b tinyint); +prepare st1 from 'update t1 set b= (str_to_date(a, a))'; +execute st1; +deallocate prepare st1; +drop table t1; End of 4.1 tests. create table t1 (a varchar(20)); insert into t1 values ('foo'); From 374ff97c85ea98ace6d792b8503b01c78354dc36 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/ramil.myoffice.izhnet.ru" <> Date: Sat, 10 Nov 2007 21:39:30 +0400 Subject: [PATCH 31/44] compiler warnings fixed. --- sql/ha_myisam.cc | 2 +- sql/unireg.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 92fa9e405e1..66f66dccd99 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -173,7 +173,7 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, pos= table_arg->key_info; for (i= 0; i < share->keys; i++, pos++) { - keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL)); + keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL)); keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) : pos->algorithm; diff --git a/sql/unireg.cc b/sql/unireg.cc index d8e63bb78e1..9e6c77d7b62 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -394,7 +394,7 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo, pos[6]=pos[7]=0; // For the future pos+=8; key_parts+=key->key_parts; - DBUG_PRINT("loop", ("flags: %d key_parts: %d at 0x%lx", + DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx", key->flags, key->key_parts, (long) key->key_part)); for (key_part=key->key_part,key_part_end=key_part+key->key_parts ; From 6889c8299724bceee804e513121df4a3815c75aa Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Sat, 17 Nov 2007 19:05:31 +0100 Subject: [PATCH 32/44] Bug#24907: unpredictable (display) precission, if input precission increases Server failed in assert() when we tried to create a DECIMAL() temp field with a scale of more than the allowed 30. Now we limit the scale to the allowed maximum. A truncation warning is thrown as necessary. --- mysql-test/r/type_newdecimal.result | 20 +++++++++++++++ mysql-test/t/type_newdecimal.test | 23 +++++++++++++++-- sql/sql_select.cc | 38 +++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 75d9582a23c..b53b49bd0dd 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1499,4 +1499,24 @@ SELECT 1 FROM t1 GROUP BY @b := @a, @b; 1 1 DROP TABLE t1; +CREATE TABLE t1 SELECT 0.123456789012345678901234567890123456 AS f1; +Warnings: +Note 1265 Data truncated for column 'f1' at row 1 +DESC t1; +Field Type Null Key Default Extra +f1 decimal(31,30) NO 0.000000000000000000000000000000 +SELECT f1 FROM t1; +f1 +0.123456789012345678901234567890 +DROP TABLE t1; +CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; +Warnings: +Warning 1264 Out of range value adjusted for column 'f1' at row 1 +DESC t1; +Field Type Null Key Default Extra +f1 decimal(59,30) NO 0.000000000000000000000000000000 +SELECT f1 FROM t1; +f1 +99999999999999999999999999999.999999999999999999999999999999 +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 5a631b6163e..cb7e0c4163a 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1195,6 +1195,25 @@ SELECT 1 FROM t1 GROUP BY @b := @a, @b; DROP TABLE t1; +# +# Bug #24907: unpredictable (display) precission, if input precission +# increases +# + +# As per 10.1.1. Overview of Numeric Types, type (new) DECIMAL has a +# maxmimum precision of 30 places after the decimal point. Show that +# temp field creation beyond that works and throws a truncation warning. +# DECIMAL(37,36) should be adjusted to DECIMAL(31,30). +CREATE TABLE t1 SELECT 0.123456789012345678901234567890123456 AS f1; +DESC t1; +SELECT f1 FROM t1; +DROP TABLE t1; + +# too many decimal places, AND too many digits altogether (90 = 45+45). +# should preserve integers (65 = 45+20) +CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; +DESC t1; +SELECT f1 FROM t1; +DROP TABLE t1; + --echo End of 5.0 tests - - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1d11f23d854..8227d09fe85 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8960,9 +8960,43 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - new_field= new Field_new_decimal(item->max_length, maybe_null, item->name, - table, item->decimals, item->unsigned_flag); + { + uint8 dec= item->decimals; + uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; + uint8 len= item->max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + overflow= my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag) - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + len -= item->decimals - dec; // corrected value fits + } + + new_field= new Field_new_decimal(len, maybe_null, item->name, + table, dec, item->unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be choosen From 909fcea6e1ef7d7925a6774ccd323685958173d5 Mon Sep 17 00:00:00 2001 From: "tnurnberg@mysql.com/white.intern.koehntopp.de" <> Date: Sat, 17 Nov 2007 19:42:16 +0100 Subject: [PATCH 33/44] Bug#24907: unpredictable (display) precission, if input precission increases post-merge fixes: some things work differently in 5.1 --- mysql-test/r/type_newdecimal.result | 2 +- sql/sql_select.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 32ee4b810b8..71be41b106f 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1521,7 +1521,7 @@ f1 DROP TABLE t1; CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; Warnings: -Warning 1264 Out of range value adjusted for column 'f1' at row 1 +Warning 1264 Out of range value for column 'f1' at row 1 DESC t1; Field Type Null Key Default Extra f1 decimal(59,30) NO 0.000000000000000000000000000000 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 65d9e3deddb..97b8f3ff14a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9219,7 +9219,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, } new_field= new Field_new_decimal(len, maybe_null, item->name, - table, dec, item->unsigned_flag); + dec, item->unsigned_flag); break; } case ROW_RESULT: From 2bcf5b4e97f7b0469e097c33052801f203eb5fcc Mon Sep 17 00:00:00 2001 From: "guilhem@gbichot4.local" <> Date: Tue, 20 Nov 2007 10:25:07 +0100 Subject: [PATCH 34/44] BUG#27850 "mysqldump --single-transaction does not work if TRUNCATE/DROP/RENAME/ALTER": this has already been closed by a note in the manual, now we complete this by a note in "mysqldump --help" --- client/mysqldump.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 4916492201b..0b4951e1cf3 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -404,8 +404,12 @@ static struct my_option my_long_options[] = "Creates a consistent snapshot by dumping all tables in a single " "transaction. Works ONLY for tables stored in storage engines which " "support multiversioning (currently only InnoDB does); the dump is NOT " - "guaranteed to be consistent for other storage engines. Option " - "automatically turns off --lock-tables.", + "guaranteed to be consistent for other storage engines. " + "While a --single-transaction dump is in process, to ensure a valid " + "dump file (correct table contents and binary log position), no other " + "connection should use the following statements: ALTER TABLE, DROP " + "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not " + "isolated from them. Option automatically turns off --lock-tables.", (gptr*) &opt_single_transaction, (gptr*) &opt_single_transaction, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-opt", OPT_SKIP_OPTIMIZATION, From 7fd9135bb89bfdd5f1465ee4f56b2c366033c747 Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Sat, 1 Dec 2007 10:05:59 +0300 Subject: [PATCH 35/44] Fix for bug #26788 "mysqld (debug) aborts when inserting specific numbers into char fields" and bug #12860 "Difference in zero padding of exponent between Unix and Windows" Rewrote the code that determines what 'precision' argument should be passed to sprintf() to fit the string representation of the input number into the field. We get finer control over conversion by pre-calculating the exponent, so we are able to determine which conversion format, 'e' or 'f', will be used by sprintf(). We also remove the leading zero from the exponent on Windows to make it compatible with the sprintf() output on other platforms. --- mysql-test/r/insert.result | 120 +++++++++++++++++++++++++++++++++++ mysql-test/t/cast.test | 2 - mysql-test/t/insert.test | 81 +++++++++++++++++++++++ mysql-test/t/type_float.test | 5 -- mysql-test/t/variables.test | 2 - sql/field.cc | 74 +++++++++++++++++---- 6 files changed, 261 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 8a0a3ba848c..0571d31fe57 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -461,4 +461,124 @@ i 2 2 DROP TABLE t1, t2; +CREATE TABLE t1 ( +a char(20) NOT NULL, +b char(7) DEFAULT NULL, +c char(4) DEFAULT NULL +); +INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0); +INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04); +INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01); +INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01); +INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01); +INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01); +INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05); +INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10); +INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15); +INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0); +INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78); +INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94); +INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203); +INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175); +INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0); +INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0); +INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); +INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +SELECT * FROM t1; +a b c +9.999999000000000748 10 10 +1.225e-05 1.2e-05 1e-0 +0.0001225 0.00012 NULL +0.122499999999999998 0.1225 NULL +0.122587699999999994 0.12259 NULL +12.25 12.25 NULL +12.25 12.25 12.2 +122500 122500 NULL +12250000000 1.2e+10 NULL +1225000000000000 1.2e+15 NULL +5000000 5000000 NULL +1.25e+78 1.2e+78 NULL +1.25e-94 1.2e-94 NULL +1.25e+203 1e+203 NULL +1.25e-175 1e-175 NULL +1.225000000000000089 NULL 1.23 +1.370000000000000107 NULL 1.37 +-1.37 NULL -1.3 +0.00187 NULL 0.00 +-0.0187 NULL -0.0 +5000 NULL 5000 +-5000 NULL -500 +DROP TABLE t1; +CREATE TABLE t1 ( +a char(20) NOT NULL, +b char(7) DEFAULT NULL, +c char(5) +); +INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0); +INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05); +INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04); +INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01); +INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01); +INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01); +INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01); +INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05); +INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10); +INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15); +INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0); +INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78); +INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94); +INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203); +INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175); +INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0); +INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0); +INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0); +INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3); +INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); +Warnings: +Warning 1265 Data truncated for column 'c' at row 1 +INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); +INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); +SELECT * FROM t1; +a b c +9.999999000000000748 10 9.999 +1.225e-05 1.2e-05 1e-05 +0.0001225 0.00012 NULL +0.122499999999999998 0.1225 NULL +0.122587699999999994 0.12259 NULL +12.25 12.25 NULL +12.25 12.25 12.25 +122500 122500 NULL +12250000000 1.2e+10 NULL +1225000000000000 1.2e+15 NULL +5000000 5000000 NULL +1.25e+78 1.2e+78 NULL +1.25e-94 1.2e-94 NULL +1.25e+203 1e+203 NULL +1.25e-175 1e-175 NULL +1.225000000000000089 NULL 1.225 +1.370000000000000107 NULL 1.37 +-1.37 NULL -1.37 +0.00187 NULL 0.002 +-0.0187 NULL -0.01 +5000 NULL 5000 +-5000 NULL -5000 +DROP TABLE t1; +CREATE TABLE t (a CHAR(10),b INT); +INSERT INTO t VALUES (),(),(); +INSERT INTO t(a) SELECT rand() FROM t; +DROP TABLE t; End of 5.0 tests. diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 316b79efe4d..fecb8677d51 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -177,8 +177,6 @@ select cast(1.0e+300 as signed int); CREATE TABLE t1 (f1 double); INSERT INTO t1 SET f1 = -1.0e+30 ; INSERT INTO t1 SET f1 = +1.0e+30 ; -# Expected result is +-1e+30, but Windows returns +-1e+030. ---replace_result 1e+030 1e+30 SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1; DROP TABLE t1; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 76177403bd0..cf67935768a 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -353,5 +353,86 @@ SELECT * FROM t2; DROP TABLE t1, t2; +# +# Bug #26788: mysqld (debug) aborts when inserting specific numbers into char +# fields +# + +CREATE TABLE t1 ( + a char(20) NOT NULL, + b char(7) DEFAULT NULL, + c char(4) DEFAULT NULL +); + +INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0); +INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05); +INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04); +INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01); +INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01); +INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01); +INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01); +INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05); +INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10); +INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15); +INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0); +INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78); +INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94); +INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203); +INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175); +INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0); +INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0); +INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0); +INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3); +INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); +INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); +INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); + +SELECT * FROM t1; + +DROP TABLE t1; + +CREATE TABLE t1 ( + a char(20) NOT NULL, + b char(7) DEFAULT NULL, + c char(5) +); + + +INSERT INTO t1(a,b,c) VALUES (9.999999e+0, 9.999999e+0, 9.999e+0); +INSERT INTO t1(a,b,c) VALUES (1.225e-05, 1.225e-05, 1.225e-05); +INSERT INTO t1(a,b) VALUES (1.225e-04, 1.225e-04); +INSERT INTO t1(a,b) VALUES (1.225e-01, 1.225e-01); +INSERT INTO t1(a,b) VALUES (1.225877e-01, 1.225877e-01); +INSERT INTO t1(a,b) VALUES (1.225e+01, 1.225e+01); +INSERT INTO t1(a,b,c) VALUES (1.225e+01, 1.225e+01, 1.225e+01); +INSERT INTO t1(a,b) VALUES (1.225e+05, 1.225e+05); +INSERT INTO t1(a,b) VALUES (1.225e+10, 1.225e+10); +INSERT INTO t1(a,b) VALUES (1.225e+15, 1.225e+15); +INSERT INTO t1(a,b) VALUES (5000000e+0, 5000000e+0); +INSERT INTO t1(a,b) VALUES (1.25e+78, 1.25e+78); +INSERT INTO t1(a,b) VALUES (1.25e-94, 1.25e-94); +INSERT INTO t1(a,b) VALUES (1.25e+203, 1.25e+203); +INSERT INTO t1(a,b) VALUES (1.25e-175, 1.25e-175); +INSERT INTO t1(a,c) VALUES (1.225e+0, 1.225e+0); +INSERT INTO t1(a,c) VALUES (1.37e+0, 1.37e+0); +INSERT INTO t1(a,c) VALUES (-1.37e+0, -1.37e+0); +INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3); +INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); +INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); +INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); + +SELECT * FROM t1; + +DROP TABLE t1; + +# +# Bug #31152: assertion in Field_str::store(double) +# + +CREATE TABLE t (a CHAR(10),b INT); +INSERT INTO t VALUES (),(),(); +INSERT INTO t(a) SELECT rand() FROM t; +DROP TABLE t; + --echo End of 5.0 tests. diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index a55200c8853..f67a1b1719b 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -116,15 +116,10 @@ drop table if exists t1; # Check conversion of floats to character field (Bug #7774) create table t1 (c char(20)); insert into t1 values (5e-28); -# Expected result is "5e-28", but windows returns "5e-028" ---replace_result 5e-028 5e-28 select * from t1; drop table t1; create table t1 (c char(6)); insert into t1 values (2e5),(2e6),(2e-4),(2e-5); -# Expected result is "2e+06", but windows returns "2e+006" -# Expected result is "2e-05", but windows returns "2e-005" ---replace_result 2e+006 2e+06 2e-005 2e-05 select * from t1; drop table t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 0ad85a32568..4b78ea6c026 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -51,8 +51,6 @@ select @test, @`test`, @TEST, @`TEST`, @"teSt"; set @select=2,@t5=1.23456; select @`select`,@not_used; set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL; -# Expected result "1e-10", windows returns "1e-010" ---replace_result 1e-010 1e-10 select @test_int,@test_double,@test_string,@test_string2,@select; set @test_int="hello",@test_double="hello",@test_string="hello",@test_string2="hello"; select @test_int,@test_double,@test_string,@test_string2; diff --git a/sql/field.cc b/sql/field.cc index 8191d885a27..c604f04339c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5907,24 +5907,70 @@ int Field_str::store(double nr) { char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; uint length; - bool use_scientific_notation= TRUE; uint local_char_length= field_length / charset()->mbmaxlen; - /* - Check fabs(nr) against longest value that can be stored in field, - which depends on whether the value is < 1 or not, and negative or not - */ double anr= fabs(nr); int neg= (nr < 0.0) ? 1 : 0; - if (local_char_length > 4 && local_char_length < 32 && - (anr < 1.0 ? anr > 1/(log_10[max(0,(int) local_char_length-neg-2)]) /* -2 for "0." */ - : anr < log_10[local_char_length-neg]-1)) - use_scientific_notation= FALSE; + uint max_length; + int exp; + uint digits; + uint i; - length= (uint) my_sprintf(buff, (buff, "%-.*g", - (use_scientific_notation ? - max(0, (int)local_char_length-neg-5) : - local_char_length), - nr)); + /* Calculate the exponent from the 'e'-format conversion */ + if (anr < 1.0 && anr > 0) + { + for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100); + for (; anr < 1e-10; exp-= 10, anr*= 1e10); + for (i= 1; anr < 1 / log_10[i]; exp--, i++); + exp--; + } + else + { + for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100); + for (; anr > 1e10; exp+= 10, anr/= 1e10); + for (i= 1; anr > log_10[i]; exp++, i++); + } + + max_length= local_char_length - neg; + + /* + Since in sprintf("%g") precision means the number of significant digits, + calculate the maximum number of significant digits if the 'f'-format + would be used (+1 for decimal point if the number has a fractional part). + */ + digits= max(0, (int) max_length - (nr != trunc(nr))); + /* + If the exponent is negative, decrease digits by the number of leading zeros + after the decimal point that do not count as significant digits. + */ + if (exp < 0) + digits= max(0, (int) digits + exp); + /* + 'e'-format is used only if the exponent is less than -4 or greater than or + equal to the precision. In this case we need to adjust the number of + significant digits to take "e+NN" + decimal point into account (hence -5). + We also have to reserve one additional character if abs(exp) >= 100. + */ + if (exp >= (int) digits || exp < -4) + digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); + + length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr)); + +#ifdef __WIN__ + /* + Windows always zero-pads the exponent to 3 digits, we want to remove the + leading 0 to match the sprintf() output on other platforms. + */ + if ((exp >= (int) digits || exp < -4) && exp > -100 && exp < 100) + { + DBUG_ASSERT(length >= 6); /* 1e+NNN */ + uint tmp= length - 3; + buff[tmp]= buff[tmp + 1]; + tmp++; + buff[tmp]= buff[tmp + 1]; + length--; + } +#endif + /* +1 below is because "precision" in %g above means the max. number of significant digits, not the output width. From 33125cd40ed2b92ee923c63bd81e153e0f5bc92c Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Sat, 1 Dec 2007 12:46:25 +0300 Subject: [PATCH 36/44] Fixed the build failure on Windows. It does not have trunc() defined in math.h, so we should not use it code. --- sql/field.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/field.cc b/sql/field.cc index c604f04339c..1878797297f 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5909,6 +5909,7 @@ int Field_str::store(double nr) uint length; uint local_char_length= field_length / charset()->mbmaxlen; double anr= fabs(nr); + bool fractional= (anr != floor(anr)); int neg= (nr < 0.0) ? 1 : 0; uint max_length; int exp; @@ -5937,7 +5938,7 @@ int Field_str::store(double nr) calculate the maximum number of significant digits if the 'f'-format would be used (+1 for decimal point if the number has a fractional part). */ - digits= max(0, (int) max_length - (nr != trunc(nr))); + digits= max(0, (int) max_length - fractional); /* If the exponent is negative, decrease digits by the number of leading zeros after the decimal point that do not count as significant digits. From 55acce750486f557b84610ce63545511aca89bed Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Sat, 1 Dec 2007 15:25:24 +0300 Subject: [PATCH 37/44] Fixed the floating point number tests on Windows. --- mysql-test/r/insert.result | 24 ++++++++++++------------ mysql-test/t/cast.test | 2 ++ mysql-test/t/insert.test | 4 +++- sql/field.cc | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result index 0571d31fe57..36cfeec1b3a 100644 --- a/mysql-test/r/insert.result +++ b/mysql-test/r/insert.result @@ -500,23 +500,23 @@ Warnings: Warning 1265 Data truncated for column 'c' at row 1 SELECT * FROM t1; a b c -9.999999000000000748 10 10 +9.999999 10 10 1.225e-05 1.2e-05 1e-0 0.0001225 0.00012 NULL -0.122499999999999998 0.1225 NULL -0.122587699999999994 0.12259 NULL +0.1225 0.1225 NULL +0.1225877 0.12259 NULL 12.25 12.25 NULL 12.25 12.25 12.2 122500 122500 NULL 12250000000 1.2e+10 NULL -1225000000000000 1.2e+15 NULL +1.225e+15 1.2e+15 NULL 5000000 5000000 NULL 1.25e+78 1.2e+78 NULL 1.25e-94 1.2e-94 NULL 1.25e+203 1e+203 NULL 1.25e-175 1e-175 NULL -1.225000000000000089 NULL 1.23 -1.370000000000000107 NULL 1.37 +1.225 NULL 1.23 +1.37 NULL 1.37 -1.37 NULL -1.3 0.00187 NULL 0.00 -0.0187 NULL -0.0 @@ -554,23 +554,23 @@ INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); SELECT * FROM t1; a b c -9.999999000000000748 10 9.999 +9.999999 10 9.999 1.225e-05 1.2e-05 1e-05 0.0001225 0.00012 NULL -0.122499999999999998 0.1225 NULL -0.122587699999999994 0.12259 NULL +0.1225 0.1225 NULL +0.1225877 0.12259 NULL 12.25 12.25 NULL 12.25 12.25 12.25 122500 122500 NULL 12250000000 1.2e+10 NULL -1225000000000000 1.2e+15 NULL +1.225e+15 1.2e+15 NULL 5000000 5000000 NULL 1.25e+78 1.2e+78 NULL 1.25e-94 1.2e-94 NULL 1.25e+203 1e+203 NULL 1.25e-175 1e-175 NULL -1.225000000000000089 NULL 1.225 -1.370000000000000107 NULL 1.37 +1.225 NULL 1.225 +1.37 NULL 1.37 -1.37 NULL -1.37 0.00187 NULL 0.002 -0.0187 NULL -0.01 diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index fecb8677d51..316b79efe4d 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -177,6 +177,8 @@ select cast(1.0e+300 as signed int); CREATE TABLE t1 (f1 double); INSERT INTO t1 SET f1 = -1.0e+30 ; INSERT INTO t1 SET f1 = +1.0e+30 ; +# Expected result is +-1e+30, but Windows returns +-1e+030. +--replace_result 1e+030 1e+30 SELECT f1 AS double_val, CAST(f1 AS SIGNED INT) AS cast_val FROM t1; DROP TABLE t1; diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index cf67935768a..3c150d0c3f6 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -386,7 +386,9 @@ INSERT INTO t1(a,c) VALUES (1.87e-3, 1.87e-3); INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); - +# Expected results are "12.2" and "1.2e+78", but Windows returns "12.3" and +# "1.3e+78" due to different rounding rules +--replace_result 12.3 12.2 1.3e+78 1.2e+78 SELECT * FROM t1; DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 1878797297f..a9aca5dc6e0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5954,7 +5954,7 @@ int Field_str::store(double nr) if (exp >= (int) digits || exp < -4) digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); - length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr)); + length= (uint) my_sprintf(buff, (buff, "%-.*g", min(digits, DBL_DIG ), nr)); #ifdef __WIN__ /* From d905aade4f5ef4c15321d57fff31f45d2952498e Mon Sep 17 00:00:00 2001 From: "kaa@polly.(none)" <> Date: Sun, 2 Dec 2007 13:49:12 +0300 Subject: [PATCH 38/44] Windows-specific fixes in floating point tests. --- mysql-test/t/insert.test | 3 +++ mysql-test/t/variables.test | 2 ++ sql/field.cc | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test index 3c150d0c3f6..5cb85d32383 100644 --- a/mysql-test/t/insert.test +++ b/mysql-test/t/insert.test @@ -423,6 +423,9 @@ INSERT INTO t1(a,c) VALUES (-1.87e-2, -1.87e-2); INSERT INTO t1(a,c) VALUES (5000e+0, 5000e+0); INSERT INTO t1(a,c) VALUES (-5000e+0, -5000e+0); +# Expected results are "12.2" and "1.2e+78", but Windows returns "12.3" and +# "1.3e+78" due to different rounding rules +--replace_result 12.3 12.2 1.3e+78 1.2e+78 SELECT * FROM t1; DROP TABLE t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 4b78ea6c026..0ad85a32568 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -51,6 +51,8 @@ select @test, @`test`, @TEST, @`TEST`, @"teSt"; set @select=2,@t5=1.23456; select @`select`,@not_used; set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL; +# Expected result "1e-10", windows returns "1e-010" +--replace_result 1e-010 1e-10 select @test_int,@test_double,@test_string,@test_string2,@select; set @test_int="hello",@test_double="hello",@test_string="hello",@test_string2="hello"; select @test_int,@test_double,@test_string,@test_string2; diff --git a/sql/field.cc b/sql/field.cc index a9aca5dc6e0..31d2af1bb14 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5953,8 +5953,11 @@ int Field_str::store(double nr) */ if (exp >= (int) digits || exp < -4) digits= max(0, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); + + /* Limit precision to DBL_DIG to avoid garbage past significant digits */ + set_if_smaller(digits, DBL_DIG); - length= (uint) my_sprintf(buff, (buff, "%-.*g", min(digits, DBL_DIG ), nr)); + length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr)); #ifdef __WIN__ /* From c3a0572d8e1f6266d49d180aac1e63f6854aa445 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Wed, 5 Dec 2007 13:54:11 -0700 Subject: [PATCH 39/44] Post-merge fix (reorder tests in ctype_ucs.test) --- mysql-test/t/ctype_ucs.test | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index e5c21bb72a0..3af5bfa54f9 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -547,14 +547,6 @@ select quote(name) from bug20536; drop table bug20536; -# -# BUG#31159 - fulltext search on ucs2 column crashes server -# -CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci); -INSERT INTO t1 VALUES('abcd'); -SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE); -DROP TABLE t1; - # # Bug #31615: crash after set names ucs2 collate xxx # @@ -567,6 +559,14 @@ set character_set_client= ucs2; --error 1231 set character_set_client= concat('ucs', substr('2', 1)); +# +# BUG#31159 - fulltext search on ucs2 column crashes server +# +CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci); +INSERT INTO t1 VALUES('abcd'); +SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE); +DROP TABLE t1; + --echo End of 4.1 tests # From 44d74f631fabcbe199be37f2b18f9f059b123309 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Thu, 6 Dec 2007 15:05:24 -0700 Subject: [PATCH 40/44] ctype-simple.c: Backport quick fix to remove Windows compiler warnings --- strings/ctype-simple.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 0355803daa8..d497eec4550 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -802,7 +802,7 @@ int my_long10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val= -(unsigned long int)val; + val= ULL(0) - (unsigned long int)val; *dst++= '-'; len--; sign= 1; @@ -838,7 +838,7 @@ int my_longlong10_to_str_8bit(CHARSET_INFO *cs __attribute__((unused)), { if (val < 0) { - val = -(ulonglong)val; + val = ULL(0) - (ulonglong)val; *dst++= '-'; len--; sign= 1; From b922c9646cbae90ff4bbe88e7c5b3d5e8be64e51 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Thu, 6 Dec 2007 16:11:26 -0700 Subject: [PATCH 41/44] Fix compiler warning about wrong integer size (probably harmless) --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2ca4b73a115..5699f1d1868 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8991,7 +8991,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, { uint8 dec= item->decimals; uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; - uint8 len= item->max_length; + uint32 len= item->max_length; /* Trying to put too many digits overall in a DECIMAL(prec,dec) From 45c78260880b66b5bb03d19b9d106a70ff457887 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Fri, 7 Dec 2007 00:54:32 -0700 Subject: [PATCH 42/44] Move the test case for bug #20901 from create.test to grant.test, so testing embedded server works correctly. --- mysql-test/r/create.result | 38 ------------------- mysql-test/r/grant.result | 39 +++++++++++++++++++ mysql-test/t/create.test | 76 ------------------------------------- mysql-test/t/grant.test | 78 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 114 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 23d2013cba5..73a9dba4e69 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -763,44 +763,6 @@ t2 CREATE TABLE `t2` ( drop table t1, t2; create table t1(a set("a,b","c,d") not null); ERROR 22007: Illegal set 'a,b' value found during parsing -create database mysqltest; -use mysqltest; -grant create on mysqltest.* to mysqltest@localhost; -create table t1 (i INT); -insert into t1 values (1); -ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' -create table t2 (i INT); -create table t4 (i INT); -grant select, insert on mysqltest.t2 to mysqltest@localhost; -grant insert on mysqltest.t4 to mysqltest@localhost; -grant create, insert on mysqltest.t5 to mysqltest@localhost; -grant create, insert on mysqltest.t6 to mysqltest@localhost; -flush privileges; -insert into t2 values (1); -create table if not exists t1 select * from t2; -ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' -create table if not exists t3 select * from t2; -ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't3' -create table if not exists t4 select * from t2; -Warnings: -Note 1050 Table 't4' already exists -create table if not exists t5 select * from t2; -create table t6 select * from t2; -create table t7 select * from t2; -ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't7' -create table t4 select * from t2; -ERROR 42S01: Table 't4' already exists -create table t1 select * from t2; -ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' -drop table t1,t2,t4,t5,t6; -revoke create on mysqltest.* from mysqltest@localhost; -revoke select, insert on mysqltest.t2 from mysqltest@localhost; -revoke insert on mysqltest.t4 from mysqltest@localhost; -revoke create, insert on mysqltest.t5 from mysqltest@localhost; -revoke create, insert on mysqltest.t6 from mysqltest@localhost; -flush privileges; -drop database mysqltest; -use test; create table t1 (i int) engine=myisam max_rows=100000000000; show create table t1; Table Create Table diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 4d402d7d0e9..5df0b4d9448 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1226,3 +1226,42 @@ drop user юзер_юзер@localhost; grant select on test.* to очень_длинный_юзер@localhost; ERROR HY000: String 'очень_длинный_юзер' is too long for user name (should be no longer than 16) set names default; +create database mysqltest; +use mysqltest; +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); +insert into t1 values (1); +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +create table t2 (i INT); +create table t4 (i INT); +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; +insert into t2 values (1); +create table if not exists t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +create table if not exists t3 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't3' +create table if not exists t4 select * from t2; +Warnings: +Note 1050 Table 't4' already exists +create table if not exists t5 select * from t2; +create table t6 select * from t2; +create table t7 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't7' +create table t4 select * from t2; +ERROR 42S01: Table 't4' already exists +create table t1 select * from t2; +ERROR 42000: INSERT command denied to user 'mysqltest'@'localhost' for table 't1' +drop table t1,t2,t4,t5,t6; +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +drop user mysqltest@localhost; +drop database mysqltest; +use test; +End of 5.1 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 15c36dfff84..45ee4c1c88d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -658,82 +658,6 @@ drop table t1, t2; --error 1367 create table t1(a set("a,b","c,d") not null); -# -# Bug #20901 - CREATE privilege is enough to insert into a table -# - -create database mysqltest; -use mysqltest; - -grant create on mysqltest.* to mysqltest@localhost; -create table t1 (i INT); - -connect (user1,localhost,mysqltest,,mysqltest); -connection user1; -# show we don't have INSERT ---error 1142 -insert into t1 values (1); -# show we have CREATE -create table t2 (i INT); -create table t4 (i INT); - -connection default; -grant select, insert on mysqltest.t2 to mysqltest@localhost; -grant insert on mysqltest.t4 to mysqltest@localhost; -# to specify ACLs for non-existent objects, must explictly |CREATE -grant create, insert on mysqltest.t5 to mysqltest@localhost; -grant create, insert on mysqltest.t6 to mysqltest@localhost; -flush privileges; - -connection user1; -insert into t2 values (1); - - -# CREATE IF NOT EXISTS...SELECT, t1 exists, no INSERT, must fail ---error 1142 -create table if not exists t1 select * from t2; - -# CREATE IF NOT EXISTS...SELECT, no t3 yet, no INSERT, must fail ---error 1142 -create table if not exists t3 select * from t2; - -# CREATE IF NOT EXISTS...SELECT, t4 exists, have INSERT, must succeed -create table if not exists t4 select * from t2; - -# CREATE IF NOT EXISTS...SELECT, no t5 yet, have INSERT, must succeed -create table if not exists t5 select * from t2; - - -# CREATE...SELECT, no t6 yet, have INSERT, must succeed -create table t6 select * from t2; - -# CREATE...SELECT, no t7 yet, no INSERT, must fail ---error 1142 -create table t7 select * from t2; - -# CREATE...SELECT, t4 exists, have INSERT, must still fail (exists) ---error 1050 -create table t4 select * from t2; - -# CREATE...SELECT, t1 exists, no INSERT, must fail ---error 1142 -create table t1 select * from t2; - - -connection default; -drop table t1,t2,t4,t5,t6; - -revoke create on mysqltest.* from mysqltest@localhost; -revoke select, insert on mysqltest.t2 from mysqltest@localhost; -revoke insert on mysqltest.t4 from mysqltest@localhost; -revoke create, insert on mysqltest.t5 from mysqltest@localhost; -revoke create, insert on mysqltest.t6 from mysqltest@localhost; -flush privileges; - -disconnect user1; -drop database mysqltest; -use test; - # End of 4.1 tests diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 8d909d63f51..73775c95d52 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1277,3 +1277,81 @@ drop user юзер_юзер@localhost; --error ER_WRONG_STRING_LENGTH grant select on test.* to очень_длинный_юзер@localhost; set names default; + +# +# Bug #20901 - CREATE privilege is enough to insert into a table +# + +create database mysqltest; +use mysqltest; + +grant create on mysqltest.* to mysqltest@localhost; +create table t1 (i INT); + +connect (user1,localhost,mysqltest,,mysqltest); +connection user1; +# show we don't have INSERT +--error 1142 +insert into t1 values (1); +# show we have CREATE +create table t2 (i INT); +create table t4 (i INT); + +connection default; +grant select, insert on mysqltest.t2 to mysqltest@localhost; +grant insert on mysqltest.t4 to mysqltest@localhost; +# to specify ACLs for non-existent objects, must explictly |CREATE +grant create, insert on mysqltest.t5 to mysqltest@localhost; +grant create, insert on mysqltest.t6 to mysqltest@localhost; +flush privileges; + +connection user1; +insert into t2 values (1); + + +# CREATE IF NOT EXISTS...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table if not exists t1 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t3 yet, no INSERT, must fail +--error 1142 +create table if not exists t3 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, t4 exists, have INSERT, must succeed +create table if not exists t4 select * from t2; + +# CREATE IF NOT EXISTS...SELECT, no t5 yet, have INSERT, must succeed +create table if not exists t5 select * from t2; + + +# CREATE...SELECT, no t6 yet, have INSERT, must succeed +create table t6 select * from t2; + +# CREATE...SELECT, no t7 yet, no INSERT, must fail +--error 1142 +create table t7 select * from t2; + +# CREATE...SELECT, t4 exists, have INSERT, must still fail (exists) +--error 1050 +create table t4 select * from t2; + +# CREATE...SELECT, t1 exists, no INSERT, must fail +--error 1142 +create table t1 select * from t2; + + +connection default; +drop table t1,t2,t4,t5,t6; + +revoke create on mysqltest.* from mysqltest@localhost; +revoke select, insert on mysqltest.t2 from mysqltest@localhost; +revoke insert on mysqltest.t4 from mysqltest@localhost; +revoke create, insert on mysqltest.t5 from mysqltest@localhost; +revoke create, insert on mysqltest.t6 from mysqltest@localhost; +drop user mysqltest@localhost; + +disconnect user1; +drop database mysqltest; +use test; + +--echo End of 5.1 tests From 6835272b3788040da5a9b746c2041423ac28fecc Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Fri, 7 Dec 2007 03:39:37 -0700 Subject: [PATCH 43/44] Make tests more robust (clean up better after grant.test) --- mysql-test/r/grant.result | 2 ++ mysql-test/t/grant.test | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 855352a2195..e27ef64af43 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1105,6 +1105,7 @@ ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table ' DROP DATABASE mysqltest1; DROP DATABASE mysqltest2; DROP USER mysqltest_1@localhost; +DROP USER mysqltest_2@localhost; use test; CREATE TABLE t1 (f1 int, f2 int); INSERT INTO t1 VALUES(1,1), (2,2); @@ -1124,6 +1125,7 @@ f1 f2 REVOKE UPDATE (f1) ON `test`.`t1` FROM 'mysqltest_1'@'localhost'; REVOKE SELECT ON `test`.* FROM 'mysqltest_1'@'localhost'; REVOKE ALL ON db27878.* FROM 'mysqltest_1'@'localhost'; +DROP USER mysqltest_1@localhost; DROP DATABASE db27878; use test; DROP TABLE t1; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 1d11a669811..ed95d90c8f8 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1122,6 +1122,7 @@ DROP DATABASE mysqltest1; DROP DATABASE mysqltest2; DROP USER mysqltest_1@localhost; +DROP USER mysqltest_2@localhost; # # Bug#27878: Unchecked privileges on a view referring to a table from another @@ -1147,6 +1148,7 @@ connection default; REVOKE UPDATE (f1) ON `test`.`t1` FROM 'mysqltest_1'@'localhost'; REVOKE SELECT ON `test`.* FROM 'mysqltest_1'@'localhost'; REVOKE ALL ON db27878.* FROM 'mysqltest_1'@'localhost'; +DROP USER mysqltest_1@localhost; DROP DATABASE db27878; use test; DROP TABLE t1; From 4eb097ba1250fcee2f5e60873624a9db50ca7a53 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Fri, 7 Dec 2007 14:43:31 -0700 Subject: [PATCH 44/44] Add a way to remove options which mysql-test-run.pl no longer uses. --- mysql-test/mysql-test-run.pl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 8428f5a63b9..42298d635e7 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -461,6 +461,19 @@ sub main () { # ############################################################################## +# +# When an option is no longer used by this program, it must be explicitly +# ignored or else it will be passed through to mysqld. GetOptions will call +# this subroutine once for each such option on the command line. See +# Getopt::Long documentation. +# + +sub warn_about_removed_option { + my ($option, $value, $hash_value) = @_; + + warn "WARNING: This option is no longer used, and is ignored: --$option\n"; +} + sub command_line_setup () { # These are defaults for things that are set on the command line @@ -498,6 +511,15 @@ sub command_line_setup () { # Read the command line # Note: Keep list, and the order, in sync with usage at end of this file + # Options that are no longer used must still be processed, because all + # unprocessed options are passed directly to mysqld. The user will be + # warned that the option is being ignored. + # + # Put the complete option string here. For example, to remove the --suite + # option, remove it from GetOptions() below and put 'suite|suites=s' here. + my @removed_options = ( + ); + Getopt::Long::Configure("pass_through"); GetOptions( # Control what engine/variation to run @@ -626,6 +648,9 @@ sub command_line_setup () { 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, + # Options which are no longer used + (map { $_ => \&warn_about_removed_option } @removed_options), + 'help|h' => \$opt_usage, ) or usage("Can't read options");