Commit 612de7c6 authored by unknown's avatar unknown

fixed view fields names check and generation (changed after Trudy review:...

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
parent 6f86198b
......@@ -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'
......@@ -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;
......@@ -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;
......
......@@ -269,6 +269,8 @@ class Item {
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 @@ class Item {
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 @@ class Item_string :public Item
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;
......
......@@ -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;
}
......
......@@ -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> &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<Item> 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<Item> it(select_lex->item_list);
it++;
while ((item= it++))
{
Item *check;
List_iterator_fast<Item> 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);
}
}
}
}
......
......@@ -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());
}
;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment