From 7c16b862137019649740c92665eb4e6580cfd2fd Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Jul 2003 14:11:08 +0300 Subject: [PATCH 01/14] after review fix --- sql/sql_select.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 31bb8ffc032..416c6389e9c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1959,9 +1959,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, break; case Item_func::OPTIMIZE_KEY: if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->key_item()->real_item())) - ->depended_from) + !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->key_item()->real_item())) ->field, @@ -1973,9 +1971,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, cond_func->functype() == Item_func::EQUAL_FUNC); if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[0]->real_item())) - ->depended_from) + !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) @@ -1985,9 +1981,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, } if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && cond_func->functype() != Item_func::LIKE_FUNC && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[1]->real_item())) - ->depended_from) + !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[1])->real_item()) @@ -2000,9 +1994,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, case Item_func::OPTIMIZE_NULL: /* column_name IS [NOT] NULL */ if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[0]->real_item())) - ->depended_from) + !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) From 3af862c7117a8c06db77709d289277a61fb79e9a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Jul 2003 14:48:47 +0300 Subject: [PATCH 02/14] Fixed test case to be more portable mysql-test/r/func_gconcat.result: Update results mysql-test/t/func_gconcat.test: Make tests repeatable. The problem is that due to floating point handling / qsort implementation the way rows are read may differ between versions --- mysql-test/r/func_gconcat.result | 4 ++-- mysql-test/t/func_gconcat.test | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index d518cff45cf..770a98f69f9 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -168,8 +168,8 @@ insert into T_REQUEST values (1,4), (5,4), (5,5); select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; REQ_ID URL -1 www.host.com -5 www.google.com,www.help.com,www.host.com +1 X +5 X,X,X drop table T_URL; drop table T_REQUEST; select group_concat(sum(a)) from t1 group by grp; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index a5a7abe3b01..6409d8106c2 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -78,6 +78,8 @@ drop table if exists T_REQUEST; create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); insert into T_REQUEST values (1,4), (5,4), (5,5); +# Make this order independent +--replace_result www.help.com X www.host.com X www.google.com X select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; drop table T_URL; From a98815346d7c46a3120f434c74fe9a807c2c0c9e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Jul 2003 17:00:01 +0500 Subject: [PATCH 03/14] Row comparison now does compare field collations, e.g. ROW('a','b','c) = ROW('A' collate latin1_bin,'b','c') returns 0 When a number is compared to a string, character sets and collations are not aggregated. e.g. this returned error in 4.1.0: SELECT 1=_latin2'1'; because character sets was aggregated, and 1 was considered as a string of latin1 charset during this aggregation. --- mysql-test/r/func_str.result | 29 +++++++++++++++++++++ mysql-test/t/func_str.test | 17 +++++++++++++ sql/item_cmpfunc.cc | 49 ++++++++++++++---------------------- sql/item_cmpfunc.h | 7 +++--- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 34c7752798d..2865a019f4b 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1,4 +1,5 @@ drop table if exists t1; +set names latin1; select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo @@ -249,6 +250,34 @@ INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); 1 DROP TABLE t1; +select 1=_latin1'1'; +1=_latin1'1' +1 +select _latin1'1'=1; +_latin1'1'=1 +1 +select _latin2'1'=1; +_latin2'1'=1 +1 +select 1=_latin2'1'; +1=_latin2'1' +1 +select _latin1'1'=_latin2'1'; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation '=' +select row('a','b','c') = row('a','b','c'); +row('a','b','c') = row('a','b','c') +1 +select row('A','b','c') = row('a','b','c'); +row('A','b','c') = row('a','b','c') +1 +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +row('A' COLLATE latin1_bin,'b','c') = row('a','b','c') +0 +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') +0 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' select POSITION(_latin1'B' IN _latin1'abcd'); POSITION(_latin1'B' IN _latin1'abcd') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index a898d3551d7..7dc08dece55 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -8,6 +8,8 @@ drop table if exists t1; --enable_warnings +set names latin1; + select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; select 'hello' 'monty'; select length('\n\t\r\b\0\_\%\\'); @@ -136,6 +138,21 @@ DROP TABLE t1; # # Test collation and coercibility # + +select 1=_latin1'1'; +select _latin1'1'=1; +select _latin2'1'=1; +select 1=_latin2'1'; +--error 1265 +select _latin1'1'=_latin2'1'; +select row('a','b','c') = row('a','b','c'); +select row('A','b','c') = row('a','b','c'); +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +--error 1265 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); + + select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a19311cd2fe..11a6e6604bf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -109,15 +109,6 @@ static bool convert_constant_item(Field *field, Item **item) } -bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables, - Item ** ref) -{ - if (Item_int_func::fix_fields(thd, tables, ref)) - return 1; - return 0; -} - - void Item_bool_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 @@ -191,8 +182,6 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_collation.set(&my_charset_bin, - DERIVATION_NONE); // For test in fix_fields return; } } @@ -206,23 +195,11 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_collation.set(&my_charset_bin, - DERIVATION_NONE); // For test in fix_fields return; } } } set_cmp_func(); - /* - We must set cmp_charset here as we may be called from for an automatic - generated item, like in natural join - */ - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - { - /* set_cmp_charset() failed */ - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); - return; - } } @@ -252,6 +229,18 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); } } + else if (type == STRING_RESULT) + { + /* + We must set cmp_charset here as we may be called from for an automatic + generated item, like in natural join + */ + if (cmp_collation.set((*a)->collation, (*b)->collation)) + { + my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name()); + return 1; + } + } return 0; } @@ -264,7 +253,7 @@ int Arg_comparator::compare_string() if ((res2= (*b)->val_str(&owner->tmp_value2))) { owner->null_value= 0; - return sortcmp(res1,res2,owner->cmp_collation.collation); + return sortcmp(res1,res2,cmp_collation.collation); } } owner->null_value= 1; @@ -278,7 +267,7 @@ int Arg_comparator::compare_e_string() res2= (*b)->val_str(&owner->tmp_value2); if (!res1 || !res2) return test(res1 == res2); - return test(sortcmp(res1, res2, owner->cmp_collation.collation) == 0); + return test(sortcmp(res1, res2, cmp_collation.collation) == 0); } @@ -502,7 +491,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value= sortcmp(a,b,cmp_collation.collation); + int value= sortcmp(a,b,cmp.cmp_collation.collation); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -1893,7 +1882,7 @@ longlong Item_func_like::val_int() null_value=0; if (canDoTurboBM) return turboBM_matches(res->ptr(), res->length()) ? 1 : 0; - return my_wildcmp(cmp_collation.collation, + return my_wildcmp(cmp.cmp_collation.collation, res->ptr(),res->ptr()+res->length(), res2->ptr(),res2->ptr()+res2->length(), escape,wild_one,wild_many) ? 0 : 1; @@ -2103,7 +2092,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) *splm1 = pattern_len; - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { int i; for (i = pattern_len - 2; i >= 0; i--) @@ -2206,7 +2195,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() for (i = bmBc; i < end; i++) *i = pattern_len; - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { for (j = 0; j < plm1; j++) bmBc[(uint) (uchar) pattern[j]] = plm1 - j; @@ -2237,7 +2226,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const const int tlmpl= text_len - pattern_len; /* Searching */ - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { while (j <= tlmpl) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1d93c9b6892..8309cd25a72 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -35,6 +35,8 @@ class Arg_comparator: public Sql_alloc Arg_comparator *comparators; // used only for compare_row() public: + DTCollation cmp_collation; + Arg_comparator() {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; @@ -112,13 +114,10 @@ class Item_bool_func2 :public Item_int_func protected: Arg_comparator cmp; String tmp_value1,tmp_value2; - DTCollation cmp_collation; public: Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) - { cmp_collation.set(0,DERIVATION_NONE);} - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref); + Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} void fix_length_and_dec(); void set_cmp_func() { From 5621263a5ca8aa8c0c05d962de32c7d6fdac8513 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Jul 2003 15:25:00 +0300 Subject: [PATCH 04/14] fixed typo in previous fix --- 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 9b6ff826dec..962d430bbd9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2050,7 +2050,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, } if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && cond_func->functype() != Item_func::LIKE_FUNC && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[1])->real_item()) From fcc962edcc8194cd79bceb8b0e12dffc53046463 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Jul 2003 19:24:38 +0500 Subject: [PATCH 05/14] FIELD() now takes in account arguments collations --- mysql-test/r/func_str.result | 19 +++++++++++ mysql-test/t/func_str.test | 13 ++++++++ sql/item_func.cc | 62 +++++++++++++++++++++++++++++++----- sql/item_func.h | 10 ++---- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 2865a019f4b..42b96956cef 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -278,6 +278,25 @@ row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') 0 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' +select FIELD('b','A','B'); +FIELD('b','A','B') +2 +select FIELD('B','A','B'); +FIELD('B','A','B') +2 +select FIELD('b' COLLATE latin1_bin,'A','B'); +FIELD('b' COLLATE latin1_bin,'A','B') +0 +select FIELD('b','A' COLLATE latin1_bin,'B'); +FIELD('b','A' COLLATE latin1_bin,'B') +0 +select FIELD(_latin2'b','A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B',1); +FIELD('b',_latin2'A','B',1) +1 select POSITION(_latin1'B' IN _latin1'abcd'); POSITION(_latin1'B' IN _latin1'abcd') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 7dc08dece55..79d2b082d01 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -152,6 +152,19 @@ select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); --error 1265 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +# +# Test FIELD() and collations +# +select FIELD('b','A','B'); +select FIELD('B','A','B'); +select FIELD('b' COLLATE latin1_bin,'A','B'); +select FIELD('b','A' COLLATE latin1_bin,'B'); +--error 1269 +select FIELD(_latin2'b','A','B'); +--error 1269 +select FIELD('b',_latin2'A','B'); +select FIELD('b',_latin2'A','B',1); + select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); diff --git a/sql/item_func.cc b/sql/item_func.cc index 41daa09521c..eba6a2cc8d1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1118,19 +1118,65 @@ longlong Item_func_locate::val_int() longlong Item_func_field::val_int() { - String *field; - if (!(field=item->val_str(&value))) - return 0; // -1 if null ? - for (uint i=0 ; i < arg_count ; i++) + if (cmp_type == STRING_RESULT) { - String *tmp_value=args[i]->val_str(&tmp); - if (tmp_value && field->length() == tmp_value->length() && - !memcmp(field->ptr(),tmp_value->ptr(),tmp_value->length())) - return (longlong) (i+1); + String *field; + if (!(field=item->val_str(&value))) + return 0; // -1 if null ? + for (uint i=0 ; i < arg_count ; i++) + { + String *tmp_value=args[i]->val_str(&tmp); + if (tmp_value && field->length() == tmp_value->length() && + !sortcmp(field,tmp_value,cmp_collation.collation)) + return (longlong) (i+1); + } + } + else if (cmp_type == INT_RESULT) + { + longlong val= item->val_int(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val_int()) + return (longlong) (i+1); + } + } + else + { + double val= item->val(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val()) + return (longlong) (i+1); + } } return 0; } +void Item_func_field::fix_length_and_dec() +{ + maybe_null=0; max_length=3; + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; + + cmp_type= item->result_type(); + for (uint i=0; i < arg_count ; i++) + cmp_type= item_cmp_type(cmp_type, args[i]->result_type()); + + if (cmp_type == STRING_RESULT) + { + cmp_collation.set(item->collation); + for (uint i=0 ; i < arg_count ; i++) + { + if (cmp_collation.aggregate(args[i]->collation)) + { + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name()); + return; + } + } + } +} + void Item_func_field::split_sum_func(Item **ref_pointer_array, List &fields) diff --git a/sql/item_func.h b/sql/item_func.h index 9ba5bea8b87..6a08d961bc3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -624,6 +624,8 @@ class Item_func_field :public Item_int_func { Item *item; String value,tmp; + Item_result cmp_type; + DTCollation cmp_collation; public: Item_func_field(Item *a,List &list) :Item_int_func(list),item(a) {} ~Item_func_field() { delete item; } @@ -641,13 +643,7 @@ public: const_item_cache&= item->const_item(); } const char *func_name() const { return "field"; } - void fix_length_and_dec() - { - maybe_null=0; max_length=3; - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - with_sum_func= with_sum_func || item->with_sum_func; - } + void fix_length_and_dec(); void set_outer_resolving() { item->set_outer_resolving(); From 9cc29f9fe4cbe348eb5d736e8b42256d8853fd6c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 01:21:42 +0300 Subject: [PATCH 06/14] Fixed problem with stacksize on Unixware --- sql/mysqld.cc | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0ea6b0778d5..0a3985c3ee9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2001,22 +2001,6 @@ static int init_common_variables(const char *conf_file_name, int argc, DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); -#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE - { - /* Retrieve used stack size; Needed for checking stack overflows */ - size_t stack_size= 0; - pthread_attr_getstacksize(&connection_attrib, &stack_size); - /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ - if (stack_size && stack_size < thread_stack) - { - if (global_system_variables.log_warnings) - sql_print_error("Warning: Asked for %ld thread stack, but got %ld", - thread_stack, stack_size); - thread_stack= stack_size; - } - } -#endif - #if defined( SET_RLIMIT_NOFILE) || defined( OS2) /* connections and databases needs lots of files */ { @@ -2366,6 +2350,21 @@ int main(int argc, char **argv) if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); pthread_attr_setstacksize(&connection_attrib,thread_stack); +#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE + { + /* Retrieve used stack size; Needed for checking stack overflows */ + size_t stack_size= 0; + pthread_attr_getstacksize(&connection_attrib, &stack_size); + /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ + if (stack_size && stack_size < thread_stack) + { + if (global_system_variables.log_warnings) + sql_print_error("Warning: Asked for %ld thread stack, but got %ld", + thread_stack, stack_size); + thread_stack= stack_size; + } + } +#endif (void) thr_setconcurrency(concurrency); // 10 by default select_thread=pthread_self(); From a7beff5e15801ffe7ce72b4f36c5f6026b48efb4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 14:41:01 +0500 Subject: [PATCH 07/14] fix and test case for the bug #787: HANDLER without INDEX doesn't work with deleted rows mysql-test/r/handler.result: test case for the bug #787: HANDLER without INDEX doesn't work with deleted rows mysql-test/t/handler.test: test case for the bug #787: HANDLER without INDEX doesn't work with deleted rows sql/sql_handler.cc: fix for the bug #787: HANDLER without INDEX doesn't work with deleted rows --- mysql-test/r/handler.result | 19 ++++++++++++++++++ mysql-test/t/handler.test | 14 +++++++++++++ sql/sql_handler.cc | 39 ++++++++++++++++--------------------- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 26b3c700d59..4e0153006f8 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -148,3 +148,22 @@ alter table t1 type=MyISAM; handler t2 read first; ERROR 42S02: Unknown table 't2' in HANDLER drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +delete from t1 limit 2; +handler t1 open; +handler t1 read first; +a +3 +handler t1 read first limit 1,1; +a +4 +handler t1 read first limit 2,2; +a +5 +6 +delete from t1 limit 3; +handler t1 read first; +a +6 +drop table t1; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 30746f10c62..15d2e954a95 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -85,3 +85,17 @@ alter table t1 type=MyISAM; handler t2 read first; drop table t1; +# +# test case for the bug #787 +# + +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +delete from t1 limit 2; +handler t1 open; +handler t1 read first; +handler t1 read first limit 1,1; +handler t1 read first limit 2,2; +delete from t1 limit 3; +handler t1 read first; +drop table t1; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 7c07c08bcac..79d13039784 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -222,6 +222,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, goto err; } + if (err == HA_ERR_RECORD_DELETED) + continue; if (err) { if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE) @@ -233,31 +235,24 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } goto ok; } - if (cond) + if (cond && !cond->val_int()) + continue; + if (!err && num_rows >= offset_limit) { - err=err; - if (!cond->val_int()) - continue; - } - if (num_rows >= offset_limit) - { - if (!err) + String *packet = &thd->packet; + Item *item; + protocol->prepare_for_resend(); + it.rewind(); + while ((item=it++)) { - String *packet = &thd->packet; - Item *item; - protocol->prepare_for_resend(); - it.rewind(); - while ((item=it++)) - { - if (item->send(thd->protocol, &buffer)) - { - protocol->free(); // Free used - my_error(ER_OUT_OF_RESOURCES,MYF(0)); - goto err; - } - } - protocol->write(); + if (item->send(thd->protocol, &buffer)) + { + protocol->free(); // Free used + my_error(ER_OUT_OF_RESOURCES,MYF(0)); + goto err; + } } + protocol->write(); } num_rows++; } From ea4b758ac0e620d59fb4d9a6e8774ae482a5661b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 12:07:06 +0200 Subject: [PATCH 08/14] enabling HA_READ_PREFIX_LAST_OR_PREV mysql-test/t/subselect.test: fixed test case for no InnoDB --- mysql-test/t/subselect.test | 2 ++ sql/opt_range.cc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 17738ae0c16..bec2303ad0c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -781,6 +781,7 @@ drop table if exists t1; # # key field overflow test # +--disable_warnings CREATE TABLE t1 ( FOLDERID VARCHAR(32)BINARY NOT NULL @@ -798,6 +799,7 @@ FOLDERID VARCHAR(32)BINARY NOT NULL , PRIMARY KEY ( FOLDERID ) ) TYPE=InnoDB; +--enable_warnings CREATE INDEX FFOLDERID_IDX ON t1 (FOLDERID); CREATE INDEX CMFLDRPARNT_IDX ON t1 (PARENTID); INSERT INTO t1 VALUES("0c9aab05b15048c59bc35c8461507deb", "System", "System", "2003-06-05 16:30:00", "The system content repository folder.", "3", "2003-06-05 16:30:00", "System", "0", NULL, "9c9aab05b15048c59bc35c8461507deb", "1"); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6c1c49e23fc..7eb66c4e30f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2637,7 +2637,7 @@ int QUICK_SELECT_DESC::get_next() else { DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); -#ifdef NOT_IMPLEMENTED_YET +#ifndef NOT_IMPLEMENTED_YET result=file->index_read(record, (byte*) range->max_key, range->max_length, ((range->flag & NEAR_MAX) ? From 3b09b2f00042d5f5e540f5f2ade54f0db5bd6239 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 18:12:23 +0500 Subject: [PATCH 09/14] New methods Item_func::agg_arg_collations() Item_func::arr_arg_collations_for_comparison() to aggregate argument collations. It helps to reuse a lot of code. --- mysql-test/r/func_str.result | 6 +++ mysql-test/t/func_str.test | 8 ++++ sql/item_func.cc | 55 ++++++++++++++++++++++++++ sql/item_func.h | 3 ++ sql/item_strfunc.cc | 75 +++++++++--------------------------- 5 files changed, 90 insertions(+), 57 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 42b96956cef..c2a921e1a54 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -278,6 +278,12 @@ row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') 0 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' +select concat(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin5_turkish_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); +ERROR HY000: Illegal mix of collations for operation 'concat' select FIELD('b','A','B'); FIELD('b','A','B') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 79d2b082d01..c9e7b1a529d 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -152,6 +152,14 @@ select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); --error 1265 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +--error 1265 +select concat(_latin1'a',_latin2'a'); +--error 1268 +select concat(_latin1'a',_latin2'a',_latin5'a'); +--error 1269 +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); + + # # Test FIELD() and collations # diff --git a/sql/item_func.cc b/sql/item_func.cc index eba6a2cc8d1..df1bce37581 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -39,6 +39,61 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } +static void my_coll_agg_error(DTCollation &c1, + DTCollation &c2, + DTCollation &c3, + const char *fname) +{ + my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + c3.collation->name,c3.derivation_name(), + fname); +} + +static void my_coll_agg_error(Item** args, uint ac, const char *fname) +{ + if (2 == ac) + my_coll_agg_error(args[0]->collation, args[1]->collation, fname); + else if (3 == ac) + my_coll_agg_error(args[0]->collation, + args[1]->collation, + args[2]->collation, + fname); + else + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); +} + +bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) +{ + uint i; + c.set(args[from]->collation); + for (i= from+1; i < argc; i++) + { + if (c.aggregate(args[i]->collation)) + { + my_coll_agg_error(args+from, argc-from, func_name()); + return TRUE; + } + } + return FALSE; +} + +bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, + uint from, uint argc) +{ + if (agg_arg_collations(c, from, argc)) + return FALSE; + + if (c.derivation == DERIVATION_NONE) + { + my_coll_agg_error(args+from, argc-from, func_name()); + return TRUE; + } + return FALSE; +} + + /* return TRUE if item is a constant */ bool diff --git a/sql/item_func.h b/sql/item_func.h index 6a08d961bc3..c7f227051f3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -135,6 +135,9 @@ public: Field *tmp_table_field(TABLE *t_arg); void set_outer_resolving(); Item *get_tmp_table_item(THD *thd); + + bool agg_arg_collations(DTCollation &c, uint from, uint argc); + bool agg_arg_collations_for_comparison(DTCollation &c, uint from, uint argc); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index cbfe98bfd21..8c3784a5d4e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -44,18 +44,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } -static void my_coll_agg3_error(DTCollation &c1, - DTCollation &c2, - DTCollation &c3, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - c3.collation->name,c3.derivation_name(), - fname); -} - uint nr_of_decimals(const char *str) { if ((str=strchr(str,'.'))) @@ -336,16 +324,11 @@ void Item_func_concat::fix_length_and_dec() bool first_coll= 1; max_length=0; - collation.set(args[0]->collation); + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) - { max_length+=args[i]->max_length; - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } if (max_length > MAX_BLOB_WIDTH) { @@ -840,13 +823,8 @@ void Item_func_replace::fix_length_and_dec() maybe_null=1; } - collation.set(args[0]->collation); - if (!collation.aggregate(args[1]->collation)) - collation.aggregate(args[2]->collation); - - if (collation.derivation == DERIVATION_NONE) - my_coll_agg3_error(args[0]->collation, args[1]->collation, - args[2]->collation, func_name()); + if (agg_arg_collations_for_comparison(collation, 0, 3)) + return; } @@ -1050,9 +1028,9 @@ void Item_func_substr::fix_length_and_dec() void Item_func_substr_index::fix_length_and_dec() { max_length= args[0]->max_length; - if (collation.set(args[0]->collation, args[1]->collation) || - (collation.derivation == DERIVATION_NONE)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + + if (agg_arg_collations_for_comparison(collation, 0, 2)) + return; } @@ -1680,20 +1658,13 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) { set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); - if (i == 0) - collation.set(args[0]->collation); - else - { - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } } maybe_null=1; // NULL if wrong first arg with_sum_func= with_sum_func || item->with_sum_func; @@ -1786,16 +1757,13 @@ void Item_func_make_set::split_sum_func(Item **ref_pointer_array, void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - collation.set(args[0]->collation); + + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) - { max_length+=args[i]->max_length; - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } + used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; @@ -2463,15 +2431,8 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - collation.set(args[1]->collation); - for (i=2 ; i < 4 && i < arg_count ; i++) - { - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } + if (agg_arg_collations(collation,1, min(4,arg_count))) + return; } String* Item_func_inet_ntoa::val_str(String* str) From a371a6e6ca04090999c69359da55f772154d9b97 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 19:56:32 +0500 Subject: [PATCH 10/14] Better arguments format to allow reuse more code --- sql/item_func.cc | 20 ++++++++++---------- sql/item_func.h | 4 ++-- sql/item_strfunc.cc | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index df1bce37581..0080a2bcff1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -64,15 +64,15 @@ static void my_coll_agg_error(Item** args, uint ac, const char *fname) my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); } -bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) +bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint ac) { uint i; - c.set(args[from]->collation); - for (i= from+1; i < argc; i++) + c.set(av[0]->collation); + for (i= 1; i < ac; i++) { - if (c.aggregate(args[i]->collation)) + if (c.aggregate(av[i]->collation)) { - my_coll_agg_error(args+from, argc-from, func_name()); + my_coll_agg_error(av, ac, func_name()); return TRUE; } } @@ -80,14 +80,14 @@ bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) } bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, - uint from, uint argc) + Item **av, uint ac) { - if (agg_arg_collations(c, from, argc)) - return FALSE; - + if (agg_arg_collations(c, av, ac)) + return TRUE; + if (c.derivation == DERIVATION_NONE) { - my_coll_agg_error(args+from, argc-from, func_name()); + my_coll_agg_error(av, ac, func_name()); return TRUE; } return FALSE; diff --git a/sql/item_func.h b/sql/item_func.h index c7f227051f3..a5575a35851 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -136,8 +136,8 @@ public: void set_outer_resolving(); Item *get_tmp_table_item(THD *thd); - bool agg_arg_collations(DTCollation &c, uint from, uint argc); - bool agg_arg_collations_for_comparison(DTCollation &c, uint from, uint argc); + bool agg_arg_collations(DTCollation &c, Item **items, uint nitems); + bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8c3784a5d4e..f46959e5365 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -324,7 +324,7 @@ void Item_func_concat::fix_length_and_dec() bool first_coll= 1; max_length=0; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -823,7 +823,7 @@ void Item_func_replace::fix_length_and_dec() maybe_null=1; } - if (agg_arg_collations_for_comparison(collation, 0, 3)) + if (agg_arg_collations_for_comparison(collation, args, 3)) return; } @@ -1029,7 +1029,7 @@ void Item_func_substr_index::fix_length_and_dec() { max_length= args[0]->max_length; - if (agg_arg_collations_for_comparison(collation, 0, 2)) + if (agg_arg_collations_for_comparison(collation, args, 2)) return; } @@ -1658,7 +1658,7 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -1758,7 +1758,7 @@ void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -2431,7 +2431,7 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - if (agg_arg_collations(collation,1, min(4,arg_count))) + if (agg_arg_collations(collation, args+1, min(4,arg_count)-1)) return; } From 0333deefd229929abda46f94148e34c36973a93b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 20:19:07 +0500 Subject: [PATCH 11/14] More code was reused --- sql/item_cmpfunc.cc | 41 +++++++---------------------------------- sql/item_func.cc | 15 ++++----------- sql/item_strfunc.cc | 3 ++- 3 files changed, 13 insertions(+), 46 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 11a6e6604bf..326138d798d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -32,18 +32,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } -static void my_coll_agg3_error(DTCollation &c1, - DTCollation &c2, - DTCollation &c3, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - c3.collation->name,c3.derivation_name(), - fname); -} - Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b) { return new Item_func_eq(a, b); @@ -572,18 +560,9 @@ void Item_func_between::fix_length_and_dec() item_cmp_type(args[1]->result_type(), args[2]->result_type())); - if (cmp_type == STRING_RESULT) - { - cmp_collation.set(args[0]->collation); - if (!cmp_collation.aggregate(args[1]->collation)) - cmp_collation.aggregate(args[2]->collation); - if (cmp_collation.derivation == DERIVATION_NONE) - { - my_coll_agg3_error(args[0]->collation, args[1]->collation, - args[2]->collation, func_name()); - return; - } - } + if (cmp_type == STRING_RESULT && + agg_arg_collations_for_comparison(cmp_collation, args, 3)) + return; /* Make a special case of compare with date/time and longlong fields. @@ -691,8 +670,8 @@ Item_func_ifnull::fix_length_and_dec() args[1]->result_type())) != REAL_RESULT) decimals= 0; - if (collation.set(args[0]->collation,args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (cached_result_type == STRING_RESULT) + agg_arg_collations(collation, args, arg_count); } @@ -768,11 +747,8 @@ Item_func_if::fix_length_and_dec() else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT) { cached_result_type = STRING_RESULT; - if (collation.set(args[1]->collation, args[2]->collation)) - { - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (agg_arg_collations(collation, args+1, 2)) return; - } } else { @@ -1972,11 +1948,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) max_length= 1; decimals= 0; - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - { - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (agg_arg_collations(cmp_collation, args, 2)) return 1; - } used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); const_item_cache=args[0]->const_item() && args[1]->const_item(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 0080a2bcff1..ad2bebf9efb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -921,14 +921,9 @@ void Item_func_min_max::fix_length_and_dec() if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); - if (i==0) - collation.set(args[0]->collation); - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } } + if (cmp_type == STRING_RESULT) + agg_arg_collations_for_comparison(collation, args, arg_count); } @@ -1103,8 +1098,7 @@ longlong Item_func_coercibility::val_int() void Item_func_locate::fix_length_and_dec() { maybe_null=0; max_length=11; - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + agg_arg_collations_for_comparison(cmp_collation, args, 2); } longlong Item_func_locate::val_int() @@ -1310,8 +1304,7 @@ void Item_func_find_in_set::fix_length_and_dec() } } } - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + agg_arg_collations_for_comparison(cmp_collation, args, 2); } static const char separator=','; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f46959e5365..2d29f76c2d7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1317,7 +1317,8 @@ void Item_func_trim::fix_length_and_dec() remove.set_ascii(" ",1); } else - if (collation.set(args[1]->collation, args[0]->collation)) + if (collation.set(args[1]->collation, args[0]->collation) || + collation.derivation == DERIVATION_NONE) { my_coll_agg_error(args[1]->collation, args[0]->collation, func_name()); } From d30c9e8e810fb222eec8c87e1f32119b22db6c6c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 10:54:10 -0700 Subject: [PATCH 12/14] Fix for send_fields flush after a fix for windows slowdown issue --- sql/sql_prepare.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fcddc2d2252..c38fb44db1c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -659,10 +659,13 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, wild_num, conds, og_num, order, group, having, proc, select_lex, unit, 0)) DBUG_RETURN(1); +#ifndef EMBEDDED_LIBRARY if (send_prep_stmt(stmt, fields.elements) || thd->protocol_simple.send_fields(&fields, 0) || + net_flush(&thd->net) || send_item_params(stmt)) DBUG_RETURN(1); +#endif join->cleanup(); } DBUG_RETURN(0); From 0f792995ec25f26a43c9f34a5f58fbf48e2dadcd Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Jul 2003 03:03:31 +0300 Subject: [PATCH 13/14] reduced using of slow current_thd/current_lex macro initialization of item_thd moved to constructor (in any case we need thd in constructor) initialization of group_concat_max_len to constructor to avoid incorrect length reporting (BUG#757) removed Item_func_group_concat::fix_length_and_dec() because item have its own fix_fields and will not have inherited items mysql-test/r/func_gconcat.result: test for BUG#757 mysql-test/t/func_gconcat.test: test for BUG#757 sql/item_sum.cc: reduced using of slow current_thd/current_lex macro initialization of item_thd moved to constructor (in any case we need thd in constructor) initialization of group_concat_max_len to constructor to avoid incorrect length reporting (BUG#757) sql/item_sum.h: removed Item_func_group_concat::fix_length_and_dec() because item have its own fix_fields and will not have inherited items --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 6 ++++++ sql/item_sum.cc | 16 ++++++++-------- sql/item_sum.h | 1 - 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 770a98f69f9..3b8d8abed9e 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -177,3 +177,12 @@ ERROR HY000: Invalid use of group function select grp,group_concat(c order by 2) from t1 group by grp; ERROR 42S22: Unknown column '2' in 'group statement' drop table t1; +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +without distinct: how it should be +1:longername,1:evenlongername +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +with distinct: cutoff at length of shortname +1:longername,1:evenlongername +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 6409d8106c2..7a13e396844 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -93,3 +93,9 @@ select group_concat(sum(a)) from t1 group by grp; select grp,group_concat(c order by 2) from t1 group by grp; drop table t1; + +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +drop table t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 67dffb35724..e16ff6969d3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1114,7 +1114,7 @@ void Item_sum_count_distinct::make_unique() bool Item_sum_count_distinct::setup(THD *thd) { List list; - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; @@ -1599,7 +1599,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, warning_available(0), key_length(0), rec_offset(0), tree_mode(0), distinct(is_distinct), warning_for_row(0), separator(is_separator), tree(&tree_base), table(0), - order(0), tables_list(0), group_concat_max_len(0), + order(0), tables_list(0), show_elements(0), arg_count_order(0), arg_count_field(0), arg_show_fields(0), count_cut_values(0) @@ -1607,8 +1607,11 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, original= 0; quick_group= 0; mark_as_sum_func(); - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + item_thd= current_thd; + SELECT_LEX *select_lex= item_thd->lex.current_select->select_lex(); order= 0; + group_concat_max_len= item_thd->variables.group_concat_max_len; + arg_show_fields= arg_count_field= is_select->elements; arg_count_order= is_order ? is_order->elements : 0; @@ -1773,7 +1776,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } result_field= 0; null_value= 1; - fix_length_and_dec(); + max_length= group_concat_max_len; thd->allow_sum_func= 1; if (!(tmp_table_param= new TMP_TABLE_PARAM)) return 1; @@ -1786,7 +1789,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool Item_func_group_concat::setup(THD *thd) { List list; - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; @@ -1873,9 +1876,6 @@ bool Item_func_group_concat::setup(THD *thd) max_elements_in_tree= ((key_length) ? thd->variables.max_heap_table_size/key_length : 1); }; - item_thd= thd; - - group_concat_max_len= thd->variables.group_concat_max_len; /* Copy table and tree_mode if they belong to this item (if item have not diff --git a/sql/item_sum.h b/sql/item_sum.h index c4876201a7c..6f0d7a028a7 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -713,7 +713,6 @@ class Item_func_group_concat : public Item_sum enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} const char *func_name() const { return "group_concat"; } enum Type type() const { return SUM_FUNC_ITEM; } - void fix_length_and_dec() { max_length=group_concat_max_len; } virtual Item_result result_type () const { return STRING_RESULT; } bool reset(); bool add(); From cd3e15a6f998a74c0f04560bd8243a04e3218d66 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Jul 2003 18:11:19 +0300 Subject: [PATCH 14/14] fixed memory leak in group_concat function (BUG#796) fixed test func_gconcat to be repeatable independent of presend tables and avoid removing user tables mysql-test/r/func_gconcat.result: removed warning in test fixed table tnames (should be tN, where N is number) mysql-test/t/func_gconcat.test: removed warning in test fixed table tnames (should be tN, where N is number) sql/item_sum.cc: added debug information fixed memory leak in group_concat function --- mysql-test/r/func_gconcat.result | 32 ++++++++++++-------------------- mysql-test/t/func_gconcat.test | 32 ++++++++++++++++---------------- sql/item_sum.cc | 18 ++++++++++++------ 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 3b8d8abed9e..15b406bcdda 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1,6 +1,4 @@ -drop table if exists t1; -Warnings: -Note 1051 Unknown table 't1' +drop table if exists t1, t2; create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); insert into t1 values (1,1,"a","a"); insert into t1 values (2,2,"b","a"); @@ -155,28 +153,22 @@ show warnings; Level Code Message Warning 1258 1 line(s) was(were) cut by group_concat() set group_concat_max_len = 1024; -drop table if exists T_URL; -Warnings: -Note 1051 Unknown table 'T_URL' -create table T_URL ( URL_ID int(11), URL varchar(80)); -drop table if exists T_REQUEST; -Warnings: -Note 1051 Unknown table 'T_REQUEST' -create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); -insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); -insert into T_REQUEST values (1,4), (5,4), (5,5); -select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where -T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; -REQ_ID URL -1 X -5 X,X,X -drop table T_URL; -drop table T_REQUEST; select group_concat(sum(a)) from t1 group by grp; ERROR HY000: Invalid use of group function select grp,group_concat(c order by 2) from t1 group by grp; ERROR 42S22: Unknown column '2' in 'group statement' drop table t1; +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +REQ_ID URL +1 X +5 X,X,X +drop table t1; +drop table t2; create table t1 (id int, name varchar(16)); insert into t1 values (1,'longername'),(1,'evenlongername'); select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 7a13e396844..f426f9ca4ee 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -1,8 +1,10 @@ # # simple test of group_concat function # +--disable_warnings +drop table if exists t1, t2; +--enable_warnings -drop table if exists t1; create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); insert into t1 values (1,1,"a","a"); insert into t1 values (2,2,"b","a"); @@ -70,21 +72,6 @@ select grp,group_concat(c) from t1 group by grp; show warnings; set group_concat_max_len = 1024; -# Test variable length - -drop table if exists T_URL; -create table T_URL ( URL_ID int(11), URL varchar(80)); -drop table if exists T_REQUEST; -create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); -insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); -insert into T_REQUEST values (1,4), (5,4), (5,5); -# Make this order independent ---replace_result www.help.com X www.host.com X www.google.com X -select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where -T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; -drop table T_URL; -drop table T_REQUEST; - # Test errors --error 1111 @@ -94,6 +81,19 @@ select grp,group_concat(c order by 2) from t1 group by grp; drop table t1; +# Test variable length + +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +# Make this order independent +--replace_result www.help.com X www.host.com X www.google.com X +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +drop table t1; +drop table t2; + create table t1 (id int, name varchar(16)); insert into t1 values (1,'longername'),(1,'evenlongername'); select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index e16ff6969d3..8d3d0de466a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1788,11 +1788,12 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool Item_func_group_concat::setup(THD *thd) { + DBUG_ENTER("Item_func_group_concat::setup"); List list; SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) - return 1; + DBUG_RETURN(1); /* all not constant fields are push to list and create temp table */ @@ -1801,7 +1802,7 @@ bool Item_func_group_concat::setup(THD *thd) { Item *item= args[i]; if (list.push_back(item)) - return 1; + DBUG_RETURN(1); if (item->const_item()) { (void) item->val_int(); @@ -1810,7 +1811,7 @@ bool Item_func_group_concat::setup(THD *thd) } } if (always_null) - return 0; + DBUG_RETURN(0); List all_fields(list); if (arg_count_order) @@ -1821,13 +1822,18 @@ bool Item_func_group_concat::setup(THD *thd) } count_field_types(tmp_table_param,all_fields,0); + if (table) + { + free_tmp_table(thd, table); + tmp_table_param->cleanup(); + } /* We have to create a temporary table for that we get descriptions of fields (types, sizes and so on). */ if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0, - 0, 0, 0,select_lex->options | thd->options))) - return 1; + 0, 0, 0,select_lex->options | thd->options))) + DBUG_RETURN(1); table->file->extra(HA_EXTRA_NO_ROWS); table->no_rows= 1; @@ -1886,7 +1892,7 @@ bool Item_func_group_concat::setup(THD *thd) original->table= table; original->tree_mode= tree_mode; } - return 0; + DBUG_RETURN(0); } /* This is used by rollup to create a separate usable copy of the function */