From: Date: June 21 2005 7:30pm Subject: bk commit into 5.0 tree (bell:1.1958) BUG#7448 List-Archive: http://lists.mysql.com/internals/26258 X-Bug: 7448 Message-Id: <20050621173056.9ADFE455D84@sanja.is.com.ua> Below is the list of changes that have just been committed into a local 5.0 repository of bell. When bell does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet 1.1958 05/06/21 20:30:48 bell@stripped +7 -0 fixed view fields names check and generation (changed after Trudy review: underlying field names treat as user set ones) (BUG#7448) sql/sql_yacc.yy 1.400 05/06/21 20:30:44 bell@stripped +11 -4 add a flag that indicates that the name of the item was an auto-generated one and so can be changed in a view sql/sql_view.cc 1.48 05/06/21 20:30:44 bell@stripped +71 -4 fixed checking of duplicates of view fields: 1) case-insensitive system charset/collation is used now to compare view filds 2) in case if the duplicate field name was of an auto-generated one, we create another unique name for it sql/item_func.cc 1.223 05/06/21 20:30:44 bell@stripped +1 -1 line made less then 80 columns sql/item.h 1.141 05/06/21 20:30:44 bell@stripped +4 -2 add a flag that indicates that the name of the item was an auto-generated one and so can be changed in a view layout fixed sql/item.cc 1.137 05/06/21 20:30:44 bell@stripped +1 -0 add a flag that indicates that the name of the item was an auto-generated one and so can be changed in a view mysql-test/t/view.test 1.72 05/06/21 20:30:44 bell@stripped +53 -0 test of view field names generation mysql-test/r/view.result 1.83 05/06/21 20:30:44 bell@stripped +55 -0 test of view field names generation # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: bell # Host: sanja.is.com.ua # Root: /home/bell/mysql/bk/work-bug4-5.0 --- 1.136/sql/item.cc Wed Jun 15 16:58:52 2005 +++ 1.137/sql/item.cc Tue Jun 21 20:30:44 2005 @@ -314,6 +314,7 @@ Item::Item(): rsize(0), name(0), orig_name(0), name_length(0), fixed(0), + is_autogenerated_name(TRUE), collation(&my_charset_bin, DERIVATION_COERCIBLE) { marker= 0; --- 1.140/sql/item.h Fri Jun 17 20:30:06 2005 +++ 1.141/sql/item.h Tue Jun 21 20:30:44 2005 @@ -269,6 +269,8 @@ my_bool unsigned_flag; my_bool with_sum_func; my_bool fixed; /* If item fixed with fix_fields */ + my_bool is_autogenerated_name; /* indicate was name of this Item + autogenerated or set by user */ DTCollation collation; // alloc & destruct is done as start of select using sql_alloc @@ -288,7 +290,7 @@ name=0; #endif } /*lint -e1509 */ - void set_name(const char *str,uint length, CHARSET_INFO *cs); + void set_name(const char *str, uint length, CHARSET_INFO *cs); void rename(char *new_name); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); @@ -1170,7 +1172,7 @@ collation.set(cs, dv); str_value.set_or_copy_aligned(str,length,cs); max_length= str_value.numchars()*cs->mbmaxlen; - set_name(name_par,0,cs); + set_name(name_par, 0, cs); decimals=NOT_FIXED_DEC; // it is constant => can be used without fix_fields (and frequently used) fixed= 1; --- 1.222/sql/item_func.cc Fri Jun 17 20:30:06 2005 +++ 1.223/sql/item_func.cc Tue Jun 21 20:30:44 2005 @@ -4620,7 +4620,7 @@ if (!(item=var->item(thd, var_type, &null_lex_string))) return 0; // Impossible thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - item->set_name(item_name, 0, system_charset_info); // Will use original name + item->set_name(item_name, 0, system_charset_info); // Will use original name return item; } --- 1.399/sql/sql_yacc.yy Fri Jun 17 22:27:21 2005 +++ 1.400/sql/sql_yacc.yy Tue Jun 21 20:30:44 2005 @@ -4107,7 +4107,10 @@ if (add_item_to_list(YYTHD, $2)) YYABORT; if ($4.str) - $2->set_name($4.str,$4.length,system_charset_info); + { + $2->set_name($4.str, $4.length, system_charset_info); + $2->is_autogenerated_name= FALSE; + } else if (!$2->name) { char *str = $1; if (str[-1] == '`') @@ -4913,9 +4916,12 @@ remember_name expr remember_end select_alias { if ($4.str) - $2->set_name($4.str,$4.length,system_charset_info); + { + $2->set_name($4.str, $4.length, system_charset_info); + $2->is_autogenerated_name= FALSE; + } else - $2->set_name($1,(uint) ($3 - $1), YYTHD->charset()); + $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $$= $2; } ; @@ -5691,7 +5697,8 @@ if (add_proc_to_list(lex->thd, $2)) YYABORT; if (!$2->name) - $2->set_name($1,(uint) ((char*) lex->tok_end - $1), YYTHD->charset()); + $2->set_name($1,(uint) ((char*) lex->tok_end - $1), + YYTHD->charset()); } ; --- 1.82/mysql-test/r/view.result Fri Jun 17 17:27:42 2005 +++ 1.83/mysql-test/r/view.result Tue Jun 21 20:30:44 2005 @@ -1743,3 +1743,58 @@ cast(1 as decimal) 1.00 drop view v1; +create view v1 as select '\\','\\shazam'; +select * from v1; +\ \shazam +\ \shazam +drop view v1; +create view v1 as select '\'','\shazam'; +select * from v1; +' shazam +' shazam +drop view v1; +create view v1 as select 'k','K'; +select * from v1; +k My_exp_K +k K +drop view v1; +create table t1 (s1 int); +create view v1 as select s1, 's1' from t1; +select * from v1; +s1 My_exp_s1 +drop view v1; +create view v1 as select 's1', s1 from t1; +select * from v1; +My_exp_s1 s1 +drop view v1; +create view v1 as select 's1', s1, 1 as My_exp_s1 from t1; +select * from v1; +My_exp_1_s1 s1 My_exp_s1 +drop view v1; +create view v1 as select 1 as My_exp_s1, 's1', s1 from t1; +select * from v1; +My_exp_s1 My_exp_1_s1 s1 +drop view v1; +create view v1 as select 1 as s1, 's1', 's1' from t1; +select * from v1; +s1 My_exp_s1 My_exp_1_s1 +drop view v1; +create view v1 as select 's1', 's1', 1 as s1 from t1; +select * from v1; +My_exp_1_s1 My_exp_s1 s1 +drop view v1; +create view v1 as select s1, 's1', 's1' from t1; +select * from v1; +s1 My_exp_s1 My_exp_1_s1 +drop view v1; +create view v1 as select 's1', 's1', s1 from t1; +select * from v1; +My_exp_1_s1 My_exp_s1 s1 +drop view v1; +create view v1 as select 1 as s1, 's1', s1 from t1; +ERROR 42S21: Duplicate column name 's1' +create view v1 as select 's1', s1, 1 as s1 from t1; +ERROR 42S21: Duplicate column name 's1' +drop table t1; +create view v1(k, K) as select 1,2; +ERROR 42S21: Duplicate column name 'K' --- 1.71/mysql-test/t/view.test Fri Jun 17 17:27:42 2005 +++ 1.72/mysql-test/t/view.test Tue Jun 21 20:30:44 2005 @@ -1587,3 +1587,56 @@ create view v1 as select cast(1 as decimal); select * from v1; drop view v1; + +# +# Generation unique names for columns, and correct names check (BUG#7448) +# +# names with ' and \ +create view v1 as select '\\','\\shazam'; +select * from v1; +drop view v1; +create view v1 as select '\'','\shazam'; +select * from v1; +drop view v1; +# autogenerated names differ by case only +create view v1 as select 'k','K'; +select * from v1; +drop view v1; +create table t1 (s1 int); +# same autogenerated names +create view v1 as select s1, 's1' from t1; +select * from v1; +drop view v1; +create view v1 as select 's1', s1 from t1; +select * from v1; +drop view v1; +# set name as one of expected autogenerated +create view v1 as select 's1', s1, 1 as My_exp_s1 from t1; +select * from v1; +drop view v1; +create view v1 as select 1 as My_exp_s1, 's1', s1 from t1; +select * from v1; +drop view v1; +# set name conflict with autogenerated names +create view v1 as select 1 as s1, 's1', 's1' from t1; +select * from v1; +drop view v1; +create view v1 as select 's1', 's1', 1 as s1 from t1; +select * from v1; +drop view v1; +# underlying field name conflict with autogenerated names +create view v1 as select s1, 's1', 's1' from t1; +select * from v1; +drop view v1; +create view v1 as select 's1', 's1', s1 from t1; +select * from v1; +drop view v1; +# underlying field name conflict with set name +-- error 1060 +create view v1 as select 1 as s1, 's1', s1 from t1; +-- error 1060 +create view v1 as select 's1', s1, 1 as s1 from t1; +drop table t1; +# set names differ by case only +-- error 1060 +create view v1(k, K) as select 1,2; --- 1.47/sql/sql_view.cc Wed Jun 15 20:58:23 2005 +++ 1.48/sql/sql_view.cc Tue Jun 21 20:30:44 2005 @@ -36,6 +36,61 @@ /* + Make a unique name for an anonymous view column + SYNOPSIS + target reference to the item for which a new name has to be made + item_list list of items within which we should check uniqueness of + the created name + last_element the last element of the list above + + NOTE + Unique names are generated by adding 'My_exp_' to the old name of the + column. In case the name that was created this way already exists, we + add a numeric postfix to its end (i.e. "1") and increase the number + until the name becomes unique. If the generated name is longer than + NAME_LEN, it is truncated. +*/ + +static void make_unique_view_field_name(Item *target, + List &item_list, + Item *last_element) +{ + char *name= (target->orig_name ? + target->orig_name : + target->name); + uint name_len; + uint attempt= 0; + char buff[NAME_LEN+1]; + for (;; attempt++) + { + Item *check; + List_iterator_fast itc(item_list); + bool ok= TRUE; + + if (attempt) + name_len= my_snprintf(buff, NAME_LEN, "My_exp_%d_%s", attempt, name); + else + name_len= my_snprintf(buff, NAME_LEN, "My_exp_%s", name); + + do + { + check= itc++; + if (check != target && + my_strcasecmp(system_charset_info, buff, check->name) == 0) + { + ok= FALSE; + break; + } + } while (check != last_element); + if (ok) + break; + } + + target->orig_name= target->name; + target->set_name(buff, name_len, system_charset_info); +} + +/* Creating/altering VIEW procedure SYNOPSIS @@ -240,24 +295,36 @@ goto err; } while ((item= it++, name= nm++)) + { item->set_name(name->str, name->length, system_charset_info); + item->is_autogenerated_name= FALSE; + } } /* Test absence of duplicates names */ { Item *item; List_iterator_fast it(select_lex->item_list); - it++; while ((item= it++)) { Item *check; List_iterator_fast itc(select_lex->item_list); + /* treat underlying fields like set by user names */ + if (item->real_item()->type() == Item::FIELD_ITEM) + item->is_autogenerated_name= FALSE; while ((check= itc++) && check != item) { - if (strcmp(item->name, check->name) == 0) + if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) { - my_error(ER_DUP_FIELDNAME, MYF(0), item->name); - DBUG_RETURN(TRUE); + if (item->is_autogenerated_name) + make_unique_view_field_name(item, select_lex->item_list, item); + else if (check->is_autogenerated_name) + make_unique_view_field_name(check, select_lex->item_list, item); + else + { + my_error(ER_DUP_FIELDNAME, MYF(0), item->name); + DBUG_RETURN(TRUE); + } } } }