Commit 1b98202b authored by unknown's avatar unknown

fixed using VIEW fields (BUG#4617)


mysql-test/r/view.result:
  using VIEW fields several times in query resolved via temporary tables
mysql-test/t/view.test:
  using VIEW fields several times in query resolved via temporary tables
sql/item.h:
  fixed using of result_field by Item_ref
sql/sql_base.cc:
  Create Item_ref as reference on VIEW fields expression reference
sql/sql_insert.cc:
  privent creating Item_ref in insert list (where Item_fields should be)
sql/sql_lex.cc:
  Item_ref creation control
sql/sql_lex.h:
  Item_ref creation control
sql/sql_update.cc:
  privent creating Item_ref in insert list (where Item_fields should be) and creation Item_fields for UPDATE list
sql/table.cc:
  Do not create Item_ref for internal view of view processing
parent dc4de8d5
......@@ -993,3 +993,18 @@ col1 col2
5 Hello, view world
drop view v2, v1;
drop table t1;
create table t1 (col1 char(5),col2 char(5));
create view v1 (col1,col2) as select col1,col2 from t1;
insert into v1 values('s1','p1'),('s1','p2'),('s1','p3'),('s1','p4'),('s2','p1'),('s3','p2'),('s4','p4');
select distinct first.col2 from t1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
col2
p1
p2
p4
select distinct first.col2 from v1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
col2
p1
p2
p4
drop view v1;
drop table t1;
......@@ -922,3 +922,14 @@ update v2 set col2='Hello, view world';
select * from t1;
drop view v2, v1;
drop table t1;
#
# using VIEW fields several times in query resolved via temporary tables
#
create table t1 (col1 char(5),col2 char(5));
create view v1 (col1,col2) as select col1,col2 from t1;
insert into v1 values('s1','p1'),('s1','p2'),('s1','p3'),('s1','p4'),('s2','p1'),('s3','p2'),('s4','p4');
select distinct first.col2 from t1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
select distinct first.col2 from v1 first where first.col2 in (select second.col2 from t1 second where second.col1<>first.col1);
drop view v1;
drop table t1;
......@@ -887,15 +887,15 @@ class Item_ref :public Item_ident
Item *orig_item; /* things in 'cleanup()' */
Item_ref(Item **hook, Item *original,const char *db_par,
const char *table_name_par, const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),ref(0), hook_ptr(hook),
orig_item(original) {}
:Item_ident(db_par, table_name_par, field_name_par), result_field(0),
ref(0), hook_ptr(hook), orig_item(original) {}
Item_ref(Item **item, Item **hook,
const char *table_name_par, const char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),
:Item_ident(NullS, table_name_par, field_name_par), result_field(0),
ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {}
// Constructor need to process subselect with temporary tables (see Item)
Item_ref(THD *thd, Item_ref *item, Item **hook)
:Item_ident(thd, item), ref(item->ref),
:Item_ident(thd, item), result_field(item->result_field), ref(item->ref),
hook_ptr(hook), orig_item(hook ? *hook : 0) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
......@@ -940,6 +940,7 @@ class Item_ref :public Item_ident
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
}
void set_result_field(Field *field) { result_field= field; }
Field *get_tmp_table_field() { return result_field; }
bool is_result_field() { return 1; }
void save_in_result_field(bool no_conversions)
{
......
......@@ -1955,7 +1955,6 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
{
if (strcmp(trans[i]->name, name) == 0)
{
*ref= trans[i];
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants_view &&
check_grant_column(thd, &table_list->grant,
......@@ -1964,6 +1963,21 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
name, length))
return WRONG_GRANT;
#endif
if (thd->lex->current_select->no_wrap_view_item)
*ref= trans[i];
else
{
Item_arena *arena= thd->current_arena, backup;
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
*ref= new Item_ref(trans + i, 0, table_list->view_name.str,
name);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
/* as far as Item_ref have defined refernce it do not need tables */
if (*ref)
(*ref)->fix_fields(thd, 0, ref);
}
return (Field*) view_ref_found;
}
}
......@@ -2441,6 +2455,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
reg2 Item *item;
List_iterator<Item> it(fields);
SELECT_LEX *select_lex= thd->lex->current_select;
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
......@@ -2452,7 +2467,10 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{
if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1))
{
select_lex->no_wrap_view_item= 0;
DBUG_RETURN(-1); /* purecov: inspected */
}
if (ref)
*(ref++)= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
......
......@@ -76,6 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
else
{ // Part field list
TABLE_LIST *save_next= table_list->next_local;
int res;
if (fields.elements != values.elements)
{
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
......@@ -86,12 +87,14 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
table_list->next_local= 0;
thd->dupp_field=0;
if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
{
thd->lex->select_lex.no_wrap_view_item= 1;
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
thd->lex->select_lex.no_wrap_view_item= 0;
table_list->next_local= save_next;
if (res)
{
return -1;
}
table_list->next_local= save_next;
if (check_unique && thd->dupp_field)
{
......
......@@ -1005,6 +1005,7 @@ void st_select_lex::init_query()
first_execution= 1;
first_cond_optimization= 1;
parsing_place= SELECT_LEX_NODE::NO_MATTER;
no_wrap_view_item= 0;
}
void st_select_lex::init_select()
......
......@@ -478,6 +478,8 @@ class st_select_lex: public st_select_lex_node
bool subquery_in_having;
bool first_execution; /* first execution in SP or PS */
bool first_cond_optimization;
/* do not wrap view fields with Item_ref */
bool no_wrap_view_item;
/*
SELECT for SELECT command st_select_lex. Used to privent scaning
......
......@@ -53,6 +53,7 @@ static bool compare_record(TABLE *table, ulong query_id)
SYNOPSIS
check_fields()
thd thread handler
items Items for check
RETURN
......@@ -60,9 +61,9 @@ static bool compare_record(TABLE *table, ulong query_id)
FALSE Items are OK
*/
static bool check_fields(List<Item> &items)
static bool check_fields(THD *thd, List<Item> &items)
{
List_iterator_fast<Item> it(items);
List_iterator<Item> it(items);
Item *item;
while ((item= it++))
{
......@@ -72,6 +73,13 @@ static bool check_fields(List<Item> &items)
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
return TRUE;
}
/*
we make temporary copy of Item_field, to avoid influence of changing
result_field on Item_ref which refer on this field
*/
Item_field *field= new Item_field(thd, (Item_field *)item);
it.replace(field);
((Item_field *)item)->register_item_tree_changing(it.ref());
}
return FALSE;
}
......@@ -139,9 +147,14 @@ int mysql_update(THD *thd,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
#endif
if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
{
thd->lex->select_lex.no_wrap_view_item= 1;
int res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
thd->lex->select_lex.no_wrap_view_item= 0;
if (res)
DBUG_RETURN(-1); /* purecov: inspected */
if (check_fields(fields))
}
if (table_list->view && check_fields(thd, fields))
{
DBUG_RETURN(-1);
}
......@@ -521,6 +534,8 @@ int mysql_multi_update_prepare(THD *thd)
List<Item> *fields= &lex->select_lex.item_list;
TABLE_LIST *tl;
table_map tables_for_update= 0, readonly_tables= 0;
int res;
bool update_view= 0;
DBUG_ENTER("mysql_multi_update_prepare");
/*
Ensure that we have update privilege for all tables and columns in the
......@@ -545,9 +560,22 @@ int mysql_multi_update_prepare(THD *thd)
time.
*/
if (setup_tables(thd, table_list, &lex->select_lex.where) ||
setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
(thd->lex->select_lex.no_wrap_view_item= 1,
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
thd->lex->select_lex.no_wrap_view_item= 0,
res))
DBUG_RETURN(-1);
if (check_fields(*fields))
for (tl= table_list; tl ; tl= tl->next_local)
{
if (tl->view)
{
update_view= 1;
break;
}
}
if (update_view && check_fields(thd, *fields))
{
DBUG_RETURN(-1);
}
......
......@@ -1505,6 +1505,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
List_iterator_fast<Item> it(select->item_list);
uint i= 0;
bool save_set_query_id= thd->set_query_id;
bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
DBUG_ENTER("st_table_list::setup_ancestor");
if (ancestor->ancestor &&
......@@ -1542,6 +1543,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
/* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex;
thd->lex->select_lex.no_wrap_view_item= 1;
/*
Resolve all view items against ancestor table.
......@@ -1596,6 +1599,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
}
ok:
thd->lex->select_lex.no_wrap_view_item= save_wrapper;
thd->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id;
DBUG_RETURN(0);
......@@ -1607,6 +1611,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
}
thd->lex->select_lex.no_wrap_view_item= save_wrapper;
thd->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id;
DBUG_RETURN(1);
......
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