From c6c887b99073d79d4da647bb2110d6ddb5af0d12 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Tue, 15 Mar 2005 17:15:47 +0400 Subject: [PATCH 01/12] # Bug#8785 Problem with nested concats and character set conversion of a string constant. --- mysql-test/r/ctype_utf8.result | 7 +++++++ mysql-test/t/ctype_utf8.test | 9 +++++++++ sql/item.cc | 12 ++++++++++++ sql/item_strfunc.cc | 3 +-- sql/sql_string.h | 4 ++++ 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 13105e2276c..314567a1544 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -861,6 +861,13 @@ user c one two DROP TABLE t1; +create table t1 (f1 varchar(1) not null) default charset utf8; +insert into t1 values (''), (''); +select concat(concat(_latin1'->',f1),_latin1'<-') from t1; +concat(concat(_latin1'->',f1),_latin1'<-') +-><- +-><- +drop table t1; select convert(_koi8r'É' using utf8) < convert(_koi8r'Ê' using utf8); convert(_koi8r'É' using utf8) < convert(_koi8r'Ê' using utf8) 1 diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 35f2b2642be..2c498cd1922 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -694,6 +694,15 @@ SELECT CHARSET('a'); SELECT user, CONCAT('<', user, '>') AS c FROM t1; DROP TABLE t1; +# +# Bug#8785 +# the same problem with the above, but with nested CONCATs +# +create table t1 (f1 varchar(1) not null) default charset utf8; +insert into t1 values (''), (''); +select concat(concat(_latin1'->',f1),_latin1'<-') from t1; +drop table t1; + # # Bug#8385: utf8_general_ci treats Cyrillic letters I and SHORT I as the same # diff --git a/sql/item.cc b/sql/item.cc index 690ada2d660..2250bd9b32c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -236,6 +236,18 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) return NULL; } conv->str_value.copy(); + /* + The above line executes str_value.realloc() internally, + which alligns Alloced_length using ALLIGN_SIZE. + In the case of Item_string::str_value we don't want + Alloced_length to be longer than str_length. + Otherwise, some functions like Item_func_concat::val_str() + try to reuse str_value as a buffer for concatenation result + for optimization purposes, so our string constant become + corrupted. See bug#8785 for more details. + Let's shrink Alloced_length to str_length to avoid this problem. + */ + conv->str_value.shrink_to_length(); return conv; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 54dd3b2d1b0..b4f75859469 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -277,8 +277,7 @@ String *Item_func_concat::val_str(String *str) current_thd->variables.max_allowed_packet); goto null; } - if (!args[0]->const_item() && - res->alloced_length() >= res->length()+res2->length()) + if (res->alloced_length() >= res->length()+res2->length()) { // Use old buffer res->append(*res2); } diff --git a/sql/sql_string.h b/sql/sql_string.h index 3ad4689cf36..8dff5558120 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -177,6 +177,10 @@ public: } } } + inline void shrink_to_length() + { + Alloced_length= str_length; + } bool is_alloced() { return alloced; } inline String& operator = (const String &s) { From 26fae361376bc8169fc4b5605e1b1e6c14c2b34c Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Tue, 15 Mar 2005 16:23:02 +0100 Subject: [PATCH 02/12] BUG#9123: If a table name is given with an underscore, then this must be properly quoted when sent to SHOW TABLES LIKE ... --- client/mysqldump.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index a53dc319b2e..cfff4d4e7ed 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2109,7 +2109,9 @@ static void get_actual_table_name(const char *old_table_name, char query[ NAME_LEN + 50 ]; DBUG_ENTER("get_actual_table_name"); - sprintf( query, "SHOW TABLES LIKE '%s'", old_table_name); + char show_name_buff[FN_REFLEN]; + sprintf(query, "SHOW TABLES LIKE %s", + quote_for_like(old_table_name, show_name_buff)); if (mysql_query_with_error_report(sock, 0, query)) { safe_exit(EX_MYSQLERR); From fde941e5b4324925cceb3b628d2415e4baa38b37 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Wed, 16 Mar 2005 01:15:45 +0200 Subject: [PATCH 03/12] Partly reverty back patch (in heap-auto-increment-key detection) to ensure that auto_key and auto_key_type are calculated the same way --- heap/hp_create.c | 3 +-- include/heap.h | 2 ++ mysql-test/mysql-test-run.sh | 2 +- sql/ha_heap.cc | 20 +++++++++++--------- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/heap/hp_create.c b/heap/hp_create.c index b1b132a16fb..af32fefea1b 100644 --- a/heap/hp_create.c +++ b/heap/hp_create.c @@ -137,8 +137,6 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, keyinfo->write_key= hp_write_key; keyinfo->hash_buckets= 0; } - if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment) - share->auto_key= i + 1; } share->min_records= min_records; share->max_records= max_records; @@ -149,6 +147,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, share->keys= keys; share->max_key_length= max_length; share->changed= 0; + share->auto_key= create_info->auto_key; share->auto_key_type= create_info->auto_key_type; share->auto_increment= create_info->auto_increment; /* Must be allocated separately for rename to work */ diff --git a/include/heap.h b/include/heap.h index 51f7b0cfa6a..badec9ce2ef 100644 --- a/include/heap.h +++ b/include/heap.h @@ -181,8 +181,10 @@ typedef struct st_heap_info LIST open_list; } HP_INFO; + typedef struct st_heap_create_info { + uint auto_key; /* keynr [1 - maxkey] for auto key */ uint auto_key_type; ulong max_table_size; ulonglong auto_increment; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 90846a2711a..aab2b1d7da2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -426,7 +426,7 @@ while test $# -gt 0; do TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` VALGRIND="$VALGRIND $TMP" ;; - --skip-ndbcluster) + --skip-ndbcluster | --skip-ndb) USE_NDBCLUSTER="" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT $1" diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index c483ab8fffa..4dc48c7422b 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -446,7 +446,6 @@ int ha_heap::create(const char *name, TABLE *table_arg, HA_KEYSEG *seg; char buff[FN_REFLEN]; int error; - bool found_real_auto_increment= 0; for (key= parts= 0; key < table_arg->keys; key++) parts+= table_arg->key_info[key].key_parts; @@ -507,20 +506,23 @@ int ha_heap::create(const char *name, TABLE *table_arg, seg->null_bit= 0; seg->null_pos= 0; } - // We have to store field->key_type() as seg->type can differ from it - if (field->flags & AUTO_INCREMENT_FLAG) + if (field->flags & AUTO_INCREMENT_FLAG && + table_arg->found_next_number_field && + key == table_arg->next_number_index) + { + /* + Store key number and type for found auto_increment key + We have to store type as seg->type can differ from it + */ + auto_key= key+ 1; auto_key_type= field->key_type(); + } } } - if (table_arg->found_next_number_field) - { - keydef[table_arg->next_number_index].flag|= HA_AUTO_KEY; - found_real_auto_increment= table_arg->next_number_key_offset == 0; - } mem_per_row+= MY_ALIGN(table_arg->reclength + 1, sizeof(char*)); HP_CREATE_INFO hp_create_info; + hp_create_info.auto_key= auto_key; hp_create_info.auto_key_type= auto_key_type; - hp_create_info.with_auto_increment= found_real_auto_increment; hp_create_info.auto_increment= (create_info->auto_increment_value ? create_info->auto_increment_value - 1 : 0); hp_create_info.max_table_size=current_thd->variables.max_heap_table_size; From ce6c390c390b1993edade781c0ee21b07eb741cc Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Tue, 15 Mar 2005 22:50:54 -0800 Subject: [PATCH 04/12] olap.result, olap.test: Added a test case for bug #8616. item.h: Fixed bug #8616. Added class Item_null_result used in rollup processing. sql_select.h, sql_select.cc: Fixed bug #8616. Added JOIN::rollup_write_data to cover rollup queries with DISTINCT. Modified other rollup methods. --- mysql-test/r/olap.result | 54 ++++++++++++++++++ mysql-test/t/olap.test | 27 +++++++++ sql/item.h | 11 ++++ sql/sql_select.cc | 118 ++++++++++++++++++++++++++++++--------- sql/sql_select.h | 3 +- 5 files changed, 186 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index bcbe5a8791c..67610108c61 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -307,3 +307,57 @@ day sample not_cancelled 2004-06-07 1 0 NULL 3 1 DROP TABLE user_day; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES +(1,4), +(2,2), (2,2), +(4,1), (4,1), (4,1), (4,1), +(2,1), (2,1); +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +4 +14 +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) +4 +6 +14 +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +4 1 +14 3 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) +4 1 +6 2 +14 3 +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(*) +4 1 +6 4 +4 4 +14 9 +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 +GROUP BY a WITH ROLLUP; +SUM(b) COUNT(DISTINCT b) COUNT(*) +4 1 1 +6 2 4 +4 1 4 +14 3 9 +DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 674b4ade097..d2ea582e58c 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -125,3 +125,30 @@ SELECT DROP TABLE user_day; +# +# Test for bug #8616: distinct sum with rollup +# + +CREATE TABLE t1 (a int, b int); + +INSERT INTO t1 VALUES + (1,4), + (2,2), (2,2), + (4,1), (4,1), (4,1), (4,1), + (2,1), (2,1); + +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; + +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 + GROUP BY a WITH ROLLUP; + +DROP TABLE t1; + diff --git a/sql/item.h b/sql/item.h index adc780677e1..e34a5f889d2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -470,6 +470,17 @@ public: Item *safe_charset_converter(CHARSET_INFO *tocs); }; +class Item_null_result :public Item_null +{ +public: + Field *result_field; + Item_null_result() : Item_null(), result_field(0) {} + bool is_result_field() { return result_field != 0; } + void save_in_result_field(bool no_conversions) + { + save_in_field(result_field, no_conversions); + } +}; /* Item represents one placeholder ('?') of prepared statement */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b00f9e422a1..0bb4c6a9402 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -157,7 +157,7 @@ static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, uint elements, List &items); static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); -static void copy_sum_funcs(Item_sum **func_ptr); +static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool init_sum_functions(Item_sum **func, Item_sum **end); static bool update_sum_func(Item_sum **func); @@ -1328,7 +1328,7 @@ JOIN::exec() if (curr_join->tmp_having) curr_join->tmp_having->update_used_tables(); if (remove_duplicates(curr_join, curr_tmp_table, - curr_join->fields_list, curr_join->tmp_having)) + *curr_fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; curr_join->tmp_having=0; curr_join->select_distinct=0; @@ -6740,26 +6740,32 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (join->procedure) join->procedure->end_group(); - if (idx < (int) join->send_group_parts) + int send_group_parts= join->send_group_parts; + if (idx < send_group_parts) { if (!join->first_record) { /* No matching rows for group function */ join->clear(); } - copy_sum_funcs(join->sum_funcs); - if (!join->having || join->having->val_int()) + copy_sum_funcs(join->sum_funcs, + join->sum_funcs_end[send_group_parts]); + if (join->having && join->having->val_int() == 0) + error= -1; + else if ((error=table->file->write_row(table->record[0]))) { - if ((error=table->file->write_row(table->record[0]))) - { - if (create_myisam_from_heap(join->thd, table, - &join->tmp_table_param, - error, 0)) - DBUG_RETURN(-1); // Not a table_is_full error - } - else - join->send_records++; + if (create_myisam_from_heap(join->thd, table, + &join->tmp_table_param, + error, 0)) + DBUG_RETURN(-1); + } + if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) + { + if (join->rollup_write_data((uint) (idx+1), table)) + error= 1; } + if (error > 0) + DBUG_RETURN(-1); if (end_of_records) DBUG_RETURN(0); } @@ -8888,11 +8894,10 @@ update_tmptable_sum_func(Item_sum **func_ptr, /* Copy result of sum functions to record in tmp_table */ static void -copy_sum_funcs(Item_sum **func_ptr) +copy_sum_funcs(Item_sum **func_ptr, Item_sum **end_ptr) { - Item_sum *func; - for (; (func = *func_ptr) ; func_ptr++) - (void) func->save_in_result_field(1); + for (; func_ptr != end_ptr ; func_ptr++) + (void) (*func_ptr)->save_in_result_field(1); return; } @@ -9013,14 +9018,16 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; - if (!(rollup.fields= (List*) thd->alloc((sizeof(Item*) + - sizeof(List) + - ref_pointer_array_size) - * send_group_parts))) + if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + + sizeof(Item**) + + sizeof(List) + + ref_pointer_array_size) + * send_group_parts ))) return 1; + + rollup.fields= (List*) (rollup.null_items + send_group_parts); rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); - rollup.item_null= new (thd->mem_root) Item_null(); /* Prepare space for field list for the different levels @@ -9028,12 +9035,16 @@ bool JOIN::rollup_init() */ for (i= 0 ; i < send_group_parts ; i++) { + rollup.null_items[i]= new (thd->mem_root) Item_null_result(); List *rollup_fields= &rollup.fields[i]; rollup_fields->empty(); rollup.ref_pointer_arrays[i]= ref_array; ref_array+= all_fields.elements; + } + for (i= 0 ; i < send_group_parts; i++) + { for (j=0 ; j < fields_list.elements ; j++) - rollup_fields->push_back(rollup.item_null); + rollup.fields[i].push_back(rollup.null_items[i]); } return 0; } @@ -9137,7 +9148,8 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, { /* Check if this is something that is part of this group by */ ORDER *group_tmp; - for (group_tmp= start_group ; group_tmp ; group_tmp= group_tmp->next) + for (group_tmp= start_group, i-- ; + group_tmp ; group_tmp= group_tmp->next, i++) { if (*group_tmp->item == item) { @@ -9146,7 +9158,9 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, set to NULL in this level */ item->maybe_null= 1; // Value will be null sometimes - item= rollup.item_null; + Item_null_result *null_item= rollup.null_items[i]; + null_item->result_field= ((Item_field *) item)->result_field; + item= null_item; break; } } @@ -9206,6 +9220,58 @@ int JOIN::rollup_send_data(uint idx) return 0; } +/* + Write all rollup levels higher than the current one to a temp table + + SYNOPSIS: + rollup_write_data() + idx Level we are on: + 0 = Total sum level + 1 = First group changed (a) + 2 = Second group changed (a,b) + table reference to temp table + + SAMPLE + SELECT a, b, SUM(c) FROM t1 GROUP BY a,b WITH ROLLUP + + RETURN + 0 ok + 1 if write_data_failed() +*/ + +int JOIN::rollup_write_data(uint idx, TABLE *table) +{ + uint i; + for (i= send_group_parts ; i-- > idx ; ) + { + /* Get reference pointers to sum functions in place */ + memcpy((char*) ref_pointer_array, + (char*) rollup.ref_pointer_arrays[i], + ref_pointer_array_size); + if ((!having || having->val_int())) + { + int error; + Item *item; + List_iterator_fast it(rollup.fields[i]); + while ((item= it++)) + { + if (item->type() == Item::NULL_ITEM && item->is_result_field()) + item->save_in_result_field(1); + } + copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); + if ((error= table->file->write_row(table->record[0]))) + { + if (create_myisam_from_heap(thd, table, &tmp_table_param, + error, 0)) + return 1; + } + } + } + /* Restore ref_pointer_array */ + set_items_ref_array(current_ref_pointer_array); + return 0; +} + /* clear results if there are not rows found for group (end_send_group/end_write_group) diff --git a/sql/sql_select.h b/sql/sql_select.h index bbd169d1850..4ea7e1b23e7 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -124,7 +124,7 @@ typedef struct st_rollup { enum State { STATE_NONE, STATE_INITED, STATE_READY }; State state; - Item *item_null; + Item_null_result **null_items; Item ***ref_pointer_arrays; List *fields; } ROLLUP; @@ -295,6 +295,7 @@ class JOIN :public Sql_alloc bool rollup_make_fields(List &all_fields, List &fields, Item_sum ***func); int rollup_send_data(uint idx); + int rollup_write_data(uint idx, TABLE *table); bool test_in_subselect(Item **where); void join_free(bool full); void clear(); From 4c3e8b078c16b30ff70cdc6c2465630a4435722a Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Wed, 16 Mar 2005 15:57:57 +0300 Subject: [PATCH 05/12] Fix for bug #7100: relay_log_space_max missing from SHOW VARIABLES --- mysql-test/r/rpl000005.result | 3 +++ mysql-test/t/rpl000005.test | 5 +++++ sql/set_var.cc | 1 + 3 files changed, 9 insertions(+) diff --git a/mysql-test/r/rpl000005.result b/mysql-test/r/rpl000005.result index 0202e43dcb2..8acfa2cbfac 100644 --- a/mysql-test/r/rpl000005.result +++ b/mysql-test/r/rpl000005.result @@ -4,6 +4,9 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +SHOW VARIABLES LIKE 'relay_log_space_limit'; +Variable_name Value +relay_log_space_limit 0 CREATE TABLE t1 (name varchar(64), age smallint(3)); INSERT INTO t1 SET name='Andy', age=31; INSERT t1 SET name='Jacob', age=2; diff --git a/mysql-test/t/rpl000005.test b/mysql-test/t/rpl000005.test index ae713633df3..b94695c72e1 100644 --- a/mysql-test/t/rpl000005.test +++ b/mysql-test/t/rpl000005.test @@ -1,5 +1,10 @@ source include/master-slave.inc; +# +# Bug#7100 relay_log_space_max missing from SHOW VARIABLES +# +SHOW VARIABLES LIKE 'relay_log_space_limit'; + CREATE TABLE t1 (name varchar(64), age smallint(3)); INSERT INTO t1 SET name='Andy', age=31; INSERT t1 SET name='Jacob', age=2; diff --git a/sql/set_var.cc b/sql/set_var.cc index 257d0a92171..d989c7d8fd2 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -845,6 +845,7 @@ struct show_var_st init_vars[]= { {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, #ifdef HAVE_REPLICATION {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS}, + {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG}, #endif {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, From 52f190c0986f1acb5e6b0b5798603280430275ef Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Wed, 16 Mar 2005 13:57:59 +0100 Subject: [PATCH 06/12] BUG#9123: Updates after Mats review --- client/mysqldump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 8df17ace780..438c338c5ef 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2107,10 +2107,10 @@ static void get_actual_table_name(const char *old_table_name, { MYSQL_RES *tableRes; MYSQL_ROW row; - char query[ NAME_LEN + 50 ]; + char query[2*NAME_LEN+50]; + char show_name_buff[FN_REFLEN]; DBUG_ENTER("get_actual_table_name"); - char show_name_buff[FN_REFLEN]; sprintf(query, "SHOW TABLES LIKE %s", quote_for_like(old_table_name, show_name_buff)); if (mysql_query_with_error_report(sock, 0, query)) From 265270b9707cf5758685ad1e856dff6924e96ef9 Mon Sep 17 00:00:00 2001 From: "monty@mysql.com" <> Date: Wed, 16 Mar 2005 15:32:43 +0200 Subject: [PATCH 07/12] Fix to get --skip-ndb to work --- mysql-test/mysql-test-run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index aab2b1d7da2..ddf69044645 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -428,8 +428,8 @@ while test $# -gt 0; do ;; --skip-ndbcluster | --skip-ndb) USE_NDBCLUSTER="" - EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" - EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT $1" + EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-ndbcluster" + EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-ndbcluster" ;; --skip-*) EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT $1" From 41487d0b4e9647e074c5f946caf219f4b837f8e7 Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Wed, 16 Mar 2005 16:44:28 +0300 Subject: [PATCH 08/12] Fix for bug#8656: Crash with group_concat on alias in outer table fixed result_field support of Item_ref --- mysql-test/r/func_gconcat.result | 7 +++++++ mysql-test/t/func_gconcat.test | 8 ++++++++ sql/item.h | 1 + 3 files changed, 16 insertions(+) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 390b33fdddc..c1ac1c084df 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -462,3 +462,10 @@ SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc NULL DROP TABLE t1; +create table r2 (a int, b int); +insert into r2 values (1,1), (2,2); +select b x, (select group_concat(x) from r2) from r2; +x (select group_concat(x) from r2) +1 1,1 +2 2,2 +drop table r2; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 6a91a7ac9c7..d32c8796075 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -284,3 +284,11 @@ drop table t1; CREATE TABLE t1 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; DROP TABLE t1; + +# +# Bug #8656: Crash with group_concat on alias in outer table +# +create table r2 (a int, b int); +insert into r2 values (1,1), (2,2); +select b x, (select group_concat(x) from r2) from r2; +drop table r2; diff --git a/sql/item.h b/sql/item.h index adc780677e1..78de2a1f58e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -902,6 +902,7 @@ public: void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } + Field *get_tmp_table_field() { return result_field; } table_map used_tables() const { return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables(); From a7b877df780ee6ce1146ee33826e9a0b29ee0ab0 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Wed, 16 Mar 2005 17:44:29 +0400 Subject: [PATCH 09/12] Bugs#9129: CHARSET(), COLLATION(), COERCIBILITY() not always correct for NULL values. Now they always result a non NULL value even the argument is NULL. It is more usefull for debugging purposes. --- mysql-test/r/func_str.result | 11 ++++++++++- mysql-test/t/func_str.test | 9 +++++++++ sql/item_func.cc | 5 ----- sql/item_strfunc.cc | 15 +++++++-------- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 855473bdc08..ab652b9d850 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -512,7 +512,7 @@ collation(make_set(255,_latin2'a',_latin2'b',_latin2'c')) coercibility(make_set( latin2_general_ci 4 select collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')), coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')); collation(export_set(255,_latin2'y',_latin2'n',_latin2' ')) coercibility(export_set(255,_latin2'y',_latin2'n',_latin2' ')) -binary 4 +latin2_general_ci 4 select collation(trim(_latin2' a ')), coercibility(trim(_latin2' a ')); collation(trim(_latin2' a ')) coercibility(trim(_latin2' a ')) latin2_general_ci 4 @@ -627,6 +627,15 @@ t1 CREATE TABLE `t1` ( `encode('abcd','ab')` binary(4) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +charset(a) collation(a) coercibility(a) +latin2 latin2_general_ci 2 +drop table t1; +select charset(null), collation(null), coercibility(null); +charset(null) collation(null) coercibility(null) +binary binary 5 select SUBSTR('abcdefg',3,2); SUBSTR('abcdefg',3,2) cd diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 4e504797a48..e7069c41716 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -368,6 +368,15 @@ select show create table t1; drop table t1; +# +# Bug#9129 +# +create table t1 (a char character set latin2); +insert into t1 values (null); +select charset(a), collation(a), coercibility(a) from t1; +drop table t1; +select charset(null), collation(null), coercibility(null); + # # test for SUBSTR # diff --git a/sql/item_func.cc b/sql/item_func.cc index 96250522c4a..ade394f90d3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1346,11 +1346,6 @@ longlong Item_func_char_length::val_int() longlong Item_func_coercibility::val_int() { DBUG_ASSERT(fixed == 1); - if (args[0]->null_value) - { - null_value= 1; - return 0; - } null_value= 0; return (longlong) args[0]->collation.derivation; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b4f75859469..8b9351d95a5 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2290,12 +2290,11 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const String *Item_func_charset::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res = args[0]->val_str(str); uint dummy_errors; - if ((null_value=(args[0]->null_value || !res->charset()))) - return 0; - str->copy(res->charset()->csname,strlen(res->charset()->csname), + CHARSET_INFO *cs= args[0]->collation.collation; + null_value= 0; + str->copy(cs->csname, strlen(cs->csname), &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2303,12 +2302,11 @@ String *Item_func_charset::val_str(String *str) String *Item_func_collation::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res = args[0]->val_str(str); uint dummy_errors; + CHARSET_INFO *cs= args[0]->collation.collation; - if ((null_value=(args[0]->null_value || !res->charset()))) - return 0; - str->copy(res->charset()->name,strlen(res->charset()->name), + null_value= 0; + str->copy(cs->name, strlen(cs->name), &my_charset_latin1, collation.collation, &dummy_errors); return str; } @@ -2472,6 +2470,7 @@ String* Item_func_export_set::val_str(String* str) uint num_set_values = 64; ulonglong mask = 0x1; str->length(0); + str->set_charset(collation.collation); /* Check if some argument is a NULL value */ if (args[0]->null_value || args[1]->null_value || args[2]->null_value) From fc6eda13361e51ae68e0036067a89ec7ce6bc4bb Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Wed, 16 Mar 2005 21:56:56 +0100 Subject: [PATCH 10/12] Fixes after Sinisa and Serg comments after push of patch for BUG#9123. BUG#9123 is solved earlier than this patch though. --- client/mysqldump.c | 93 ++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 438c338c5ef..0ff88bcbc73 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -871,8 +871,8 @@ static int dbConnect(char *host, char *user,char *passwd) cannot reconnect. */ sock->reconnect= 0; - sprintf(buff, "/*!40100 SET @@SQL_MODE='%s' */", - compatible_mode_normal_str); + my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */", + compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { mysql_close(sock); @@ -1107,8 +1107,9 @@ static uint getTableStructure(char *table, char* db) if (verbose) fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); - sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", - (opt_quoted || opt_keywords)); + my_snprintf(insert_pat, sizeof(insert_pat), + "SET OPTION SQL_QUOTE_SHOW_CREATE=%d", + (opt_quoted || opt_keywords)); if (!create_options) strmov(strend(insert_pat), "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */"); @@ -1126,7 +1127,7 @@ static uint getTableStructure(char *table, char* db) /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; - sprintf(buff,"show create table %s", result_table); + my_snprintf(buff, sizeof(buff), "show create table %s", result_table); if (mysql_query_with_error_report(sock, 0, buff)) { safe_exit(EX_MYSQLERR); @@ -1164,7 +1165,8 @@ static uint getTableStructure(char *table, char* db) check_io(sql_file); mysql_free_result(tableRes); } - sprintf(insert_pat,"show fields from %s", result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", + result_table); if (mysql_query_with_error_report(sock, &tableRes, insert_pat)) { if (path) @@ -1174,11 +1176,12 @@ static uint getTableStructure(char *table, char* db) } if (cFlag) - sprintf(insert_pat, "INSERT %sINTO %s (", delayed, opt_quoted_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", + delayed, opt_quoted_table); else { - sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, - opt_quoted_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ", + delayed, opt_quoted_table); if (!extended_insert) strcat(insert_pat,"("); } @@ -1205,7 +1208,8 @@ static uint getTableStructure(char *table, char* db) "%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", my_progname, mysql_error(sock)); - sprintf(insert_pat,"show fields from %s", result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "show fields from %s", + result_table); if (mysql_query_with_error_report(sock, &tableRes, insert_pat)) { safe_exit(EX_MYSQLERR); @@ -1240,10 +1244,12 @@ static uint getTableStructure(char *table, char* db) check_io(sql_file); } if (cFlag) - sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s (", + delayed, result_table); else { - sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, result_table); + my_snprintf(insert_pat, sizeof(insert_pat), "INSERT %sINTO %s VALUES ", + delayed, result_table); if (!extended_insert) strcat(insert_pat,"("); } @@ -1300,7 +1306,7 @@ static uint getTableStructure(char *table, char* db) /* Make an sql-file, if path was given iow. option -T was given */ char buff[20+FN_REFLEN]; uint keynr,primary_key; - sprintf(buff,"show keys from %s", result_table); + my_snprintf(buff, sizeof(buff), "show keys from %s", result_table); if (mysql_query_with_error_report(sock, &tableRes, buff)) { if (path) @@ -1370,8 +1376,12 @@ static uint getTableStructure(char *table, char* db) if (create_options) { char show_name_buff[FN_REFLEN]; - sprintf(buff,"show table status like %s", - quote_for_like(table, show_name_buff)); + + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(table) < sizeof(show_name_buff)); + my_snprintf(buff, sizeof(buff), "show table status like %s", + quote_for_like(table, show_name_buff)); + if (mysql_query_with_error_report(sock, &tableRes, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) @@ -1531,8 +1541,9 @@ static void dumpTable(uint numFields, char *table) my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if filename wasn't deleted */ to_unix_path(filename); - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", - filename); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", + filename); end= strend(query); if (fields_terminated || enclosed || opt_enclosed || escaped) @@ -1544,7 +1555,7 @@ static void dumpTable(uint numFields, char *table) end= add_load_option(end, lines_terminated, " LINES TERMINATED BY"); *end= '\0'; - sprintf(buff," FROM %s", result_table); + my_snprintf(buff, sizeof(buff), " FROM %s", result_table); end= strmov(end,buff); if (where || order_by) { @@ -1572,8 +1583,9 @@ static void dumpTable(uint numFields, char *table) result_table); check_io(md_result_file); } - sprintf(query, "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", - result_table); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", + result_table); if (where || order_by) { query = alloc_query_str((ulong) (strlen(query) + 1 + @@ -1671,8 +1683,9 @@ static void dumpTable(uint numFields, char *table) int is_blob; if (!(field = mysql_fetch_field(res))) { - sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", - my_progname, result_table); + my_snprintf(query, QUERY_LENGTH, + "%s: Not enough fields from table %s! Aborting.\n", + my_progname, result_table); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -1873,12 +1886,13 @@ static void dumpTable(uint numFields, char *table) check_io(md_result_file); if (mysql_errno(sock)) { - sprintf(query,"%s: Error %d: %s when dumping table %s at row: %ld\n", - my_progname, - mysql_errno(sock), - mysql_error(sock), - result_table, - rownr); + my_snprintf(query, QUERY_LENGTH, + "%s: Error %d: %s when dumping table %s at row: %ld\n", + my_progname, + mysql_errno(sock), + mysql_error(sock), + result_table, + rownr); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -1994,8 +2008,9 @@ static int init_dumping(char *database) MYSQL_ROW row; MYSQL_RES *dbinfo; - sprintf(qbuf,"SHOW CREATE DATABASE IF NOT EXISTS %s", - qdatabase); + my_snprintf(qbuf, sizeof(qbuf), + "SHOW CREATE DATABASE IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { @@ -2107,12 +2122,15 @@ static void get_actual_table_name(const char *old_table_name, { MYSQL_RES *tableRes; MYSQL_ROW row; - char query[2*NAME_LEN+50]; + char query[50 + 2*NAME_LEN]; char show_name_buff[FN_REFLEN]; DBUG_ENTER("get_actual_table_name"); - sprintf(query, "SHOW TABLES LIKE %s", - quote_for_like(old_table_name, show_name_buff)); + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); + my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", + quote_for_like(old_table_name, show_name_buff)); + if (mysql_query_with_error_report(sock, 0, query)) { safe_exit(EX_MYSQLERR); @@ -2357,8 +2375,10 @@ static const char *check_if_ignore_table(const char *table_name) MYSQL_ROW row; const char *result= 0; - sprintf(buff,"show table status like %s", - quote_for_like(table_name, show_name_buff)); + /* Check memory for quote_for_like() */ + DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); + my_snprintf(buff, sizeof(buff), "show table status like %s", + quote_for_like(table_name, show_name_buff)); if (mysql_query_with_error_report(sock, &res, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) @@ -2411,7 +2431,8 @@ static char *primary_key_fields(const char *table_name) uint result_length = 0; char *result = 0; - sprintf(show_keys_buff, "SHOW KEYS FROM %s", table_name); + my_snprintf(show_keys_buff, sizeof(show_keys_buff), + "SHOW KEYS FROM %s", table_name); if (mysql_query(sock, show_keys_buff) || !(res = mysql_store_result(sock))) { From 45ba13889de9e4ebfac8ca1052e042c150aec102 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Wed, 16 Mar 2005 15:55:04 -0800 Subject: [PATCH 11/12] olap.result, olap.test: Added a test for bug #8615. sql_select.cc: Fixed bug #8615. This fix only removed the cause of the reported crash. It does not resolve other problems of rollup queries with DISTINCT. They were fixed in the previous patch for bug 8616. --- mysql-test/r/olap.result | 18 ++++++++++++++++++ mysql-test/t/olap.test | 5 ++++- sql/sql_select.cc | 7 ++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 67610108c61..fe83800f658 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -360,4 +360,22 @@ SUM(b) COUNT(DISTINCT b) COUNT(*) 6 2 4 4 1 4 14 3 9 +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +1 4 +2 2 +2 4 +2 6 +4 4 +4 4 +NULL 14 +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +a sum(b) +1 4 +2 2 +2 4 +2 6 +4 4 +NULL 14 DROP TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index d2ea582e58c..6778af3d533 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -126,7 +126,7 @@ SELECT DROP TABLE user_day; # -# Test for bug #8616: distinct sum with rollup +# Tests for bugs #8616, #8615: distinct sum with rollup # CREATE TABLE t1 (a int, b int); @@ -150,5 +150,8 @@ SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, sum(b) FROM t1 GROUP BY a,b WITH ROLLUP; + DROP TABLE t1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0bb4c6a9402..5bfe1346568 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1269,7 +1269,6 @@ JOIN::exec() { DBUG_VOID_RETURN; } - curr_join->group_list= 0; } thd->proc_info="Copying to group table"; @@ -1289,8 +1288,10 @@ JOIN::exec() } } if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, - 1) || - (tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, + 1)) + DBUG_VOID_RETURN; + curr_join->group_list= 0; + if ((tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, 0))) { error= tmp_error; From a773916238d9bece75458b9548e08fac303cdc8a Mon Sep 17 00:00:00 2001 From: "ramil@mysql.com" <> Date: Thu, 17 Mar 2005 10:24:50 +0400 Subject: [PATCH 12/12] A fix (bug #8942: SUBSTRING_INDEX in UPDATE causes internal loop). --- mysql-test/r/update.result | 7 +++++++ mysql-test/t/update.test | 10 ++++++++++ sql/key.cc | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 7810d52d156..9ca92fe75df 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -209,3 +209,10 @@ insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; drop table t1, t2; +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +a b +0 2 +drop table t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 62439dcc51b..6c7b450f763 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -164,3 +164,13 @@ insert into t1 values (1, "t1c2-1", 10), (2, "t1c2-2", 20); update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1"; update t1 left join t2 on t1.c1 = t2.c1 set t2.c2 = "t2c2-1" where t1.c3 = 10; drop table t1, t2; + +# +# Bug #8942: a problem with update and partial key part +# + +create table t1 (a int, b char(255), key(a, b(20))); +insert into t1 values (0, '1'); +update t1 set b = b + 1 where a = 0; +select * from t1; +drop table t1; diff --git a/sql/key.cc b/sql/key.cc index 0a5937fc881..52eb108a5df 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -265,7 +265,7 @@ bool check_if_key_used(TABLE *table, uint idx, List &fields) f.rewind(); while ((field=(Item_field*) f++)) { - if (key_part->field == field->field) + if (key_part->field->eq(field->field)) return 1; } }