From 612de7c64346317f2427917beacc483e9d1e3b05 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 20:30:48 +0300 Subject: [PATCH] fixed view fields names check and generation (changed after Trudy review: underlying field names treat as user set ones) (BUG#7448) mysql-test/r/view.result: test of view field names generation mysql-test/t/view.test: test of view field names generation sql/item.cc: 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/item.h: 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_func.cc: line made less then 80 columns sql/sql_view.cc: 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/sql_yacc.yy: 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/r/view.result | 55 +++++++++++++++++++++++++++++ mysql-test/t/view.test | 53 ++++++++++++++++++++++++++++ sql/item.cc | 1 + sql/item.h | 6 ++-- sql/item_func.cc | 2 +- sql/sql_view.cc | 75 +++++++++++++++++++++++++++++++++++++--- sql/sql_yacc.yy | 15 +++++--- 7 files changed, 196 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b178af1bb1c..99bf11ef9d8 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1743,3 +1743,58 @@ select * from v1; 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' diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 23d482254d1..dee5c62b1fe 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1587,3 +1587,56 @@ drop table t1; 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; diff --git a/sql/item.cc b/sql/item.cc index e7feeaa4289..2276758e284 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -314,6 +314,7 @@ void *Item::operator new(size_t size, Item *reuse, uint *rsize) 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; diff --git a/sql/item.h b/sql/item.h index 6a1490a19d5..afaefe9a096 100644 --- a/sql/item.h +++ b/sql/item.h @@ -269,6 +269,8 @@ public: 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 @@ public: 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 @@ public: 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; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4166605ae11..57f68bbc2a0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4620,7 +4620,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name, 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; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 5152619fd85..0b351407c13 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -35,6 +35,61 @@ TYPELIB updatable_views_with_limit_typelib= }; +/* + 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 @@ -240,24 +295,36 @@ bool mysql_create_view(THD *thd, 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); + } } } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00ef8b581f1..1b9176e2744 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4107,7 +4107,10 @@ select_item: 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 @@ udf_expr: 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 @@ procedure_item: 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()); } ;