Commit f5328c02 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 af14cae0
...@@ -993,3 +993,18 @@ col1 col2 ...@@ -993,3 +993,18 @@ col1 col2
5 Hello, view world 5 Hello, view world
drop view v2, v1; drop view v2, v1;
drop table t1; 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'; ...@@ -922,3 +922,14 @@ update v2 set col2='Hello, view world';
select * from t1; select * from t1;
drop view v2, v1; drop view v2, v1;
drop table t1; 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 ...@@ -887,15 +887,15 @@ class Item_ref :public Item_ident
Item *orig_item; /* things in 'cleanup()' */ Item *orig_item; /* things in 'cleanup()' */
Item_ref(Item **hook, Item *original,const char *db_par, Item_ref(Item **hook, Item *original,const char *db_par,
const char *table_name_par, const char *field_name_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), :Item_ident(db_par, table_name_par, field_name_par), result_field(0),
orig_item(original) {} ref(0), hook_ptr(hook), orig_item(original) {}
Item_ref(Item **item, Item **hook, Item_ref(Item **item, Item **hook,
const char *table_name_par, const char *field_name_par) 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) {} ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {}
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_ref(THD *thd, Item_ref *item, Item **hook) 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) {} hook_ptr(hook), orig_item(hook ? *hook : 0) {}
enum Type type() const { return REF_ITEM; } enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const bool eq(const Item *item, bool binary_cmp) const
...@@ -940,6 +940,7 @@ class Item_ref :public Item_ident ...@@ -940,6 +940,7 @@ class Item_ref :public Item_ident
return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables(); return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables();
} }
void set_result_field(Field *field) { result_field= field; } void set_result_field(Field *field) { result_field= field; }
Field *get_tmp_table_field() { return result_field; }
bool is_result_field() { return 1; } bool is_result_field() { return 1; }
void save_in_result_field(bool no_conversions) void save_in_result_field(bool no_conversions)
{ {
......
...@@ -1955,7 +1955,6 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list, ...@@ -1955,7 +1955,6 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
{ {
if (strcmp(trans[i]->name, name) == 0) if (strcmp(trans[i]->name, name) == 0)
{ {
*ref= trans[i];
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants_view && if (check_grants_view &&
check_grant_column(thd, &table_list->grant, check_grant_column(thd, &table_list->grant,
...@@ -1964,6 +1963,21 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list, ...@@ -1964,6 +1963,21 @@ Field *find_field_in_table(THD *thd, TABLE_LIST *table_list,
name, length)) name, length))
return WRONG_GRANT; return WRONG_GRANT;
#endif #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; return (Field*) view_ref_found;
} }
} }
...@@ -2441,6 +2455,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ...@@ -2441,6 +2455,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
{ {
reg2 Item *item; reg2 Item *item;
List_iterator<Item> it(fields); List_iterator<Item> it(fields);
SELECT_LEX *select_lex= thd->lex->current_select;
DBUG_ENTER("setup_fields"); DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id; thd->set_query_id=set_query_id;
...@@ -2452,7 +2467,10 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ...@@ -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()) || if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1)) (item= *(it.ref()))->check_cols(1))
{
select_lex->no_wrap_view_item= 0;
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
}
if (ref) if (ref)
*(ref++)= item; *(ref++)= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_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, ...@@ -76,6 +76,7 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
else else
{ // Part field list { // Part field list
TABLE_LIST *save_next= table_list->next_local; TABLE_LIST *save_next= table_list->next_local;
int res;
if (fields.elements != values.elements) if (fields.elements != values.elements)
{ {
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, 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, ...@@ -86,12 +87,14 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
table_list->next_local= 0; table_list->next_local= 0;
thd->dupp_field=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)
{ {
table_list->next_local= save_next;
return -1; return -1;
} }
table_list->next_local= save_next;
if (check_unique && thd->dupp_field) if (check_unique && thd->dupp_field)
{ {
......
...@@ -1005,6 +1005,7 @@ void st_select_lex::init_query() ...@@ -1005,6 +1005,7 @@ void st_select_lex::init_query()
first_execution= 1; first_execution= 1;
first_cond_optimization= 1; first_cond_optimization= 1;
parsing_place= SELECT_LEX_NODE::NO_MATTER; parsing_place= SELECT_LEX_NODE::NO_MATTER;
no_wrap_view_item= 0;
} }
void st_select_lex::init_select() void st_select_lex::init_select()
......
...@@ -478,6 +478,8 @@ class st_select_lex: public st_select_lex_node ...@@ -478,6 +478,8 @@ class st_select_lex: public st_select_lex_node
bool subquery_in_having; bool subquery_in_having;
bool first_execution; /* first execution in SP or PS */ bool first_execution; /* first execution in SP or PS */
bool first_cond_optimization; 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 SELECT for SELECT command st_select_lex. Used to privent scaning
......
...@@ -53,6 +53,7 @@ static bool compare_record(TABLE *table, ulong query_id) ...@@ -53,6 +53,7 @@ static bool compare_record(TABLE *table, ulong query_id)
SYNOPSIS SYNOPSIS
check_fields() check_fields()
thd thread handler
items Items for check items Items for check
RETURN RETURN
...@@ -60,9 +61,9 @@ static bool compare_record(TABLE *table, ulong query_id) ...@@ -60,9 +61,9 @@ static bool compare_record(TABLE *table, ulong query_id)
FALSE Items are OK 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; Item *item;
while ((item= it++)) while ((item= it++))
{ {
...@@ -72,6 +73,13 @@ static bool check_fields(List<Item> &items) ...@@ -72,6 +73,13 @@ static bool check_fields(List<Item> &items)
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name); my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
return TRUE; 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; return FALSE;
} }
...@@ -139,9 +147,14 @@ int mysql_update(THD *thd, ...@@ -139,9 +147,14 @@ int mysql_update(THD *thd,
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
#endif #endif
if (setup_fields(thd, 0, table_list, fields, 1, 0, 0)) {
DBUG_RETURN(-1); /* purecov: inspected */ thd->lex->select_lex.no_wrap_view_item= 1;
if (check_fields(fields)) 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 (table_list->view && check_fields(thd, fields))
{ {
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
...@@ -521,6 +534,8 @@ int mysql_multi_update_prepare(THD *thd) ...@@ -521,6 +534,8 @@ int mysql_multi_update_prepare(THD *thd)
List<Item> *fields= &lex->select_lex.item_list; List<Item> *fields= &lex->select_lex.item_list;
TABLE_LIST *tl; TABLE_LIST *tl;
table_map tables_for_update= 0, readonly_tables= 0; table_map tables_for_update= 0, readonly_tables= 0;
int res;
bool update_view= 0;
DBUG_ENTER("mysql_multi_update_prepare"); DBUG_ENTER("mysql_multi_update_prepare");
/* /*
Ensure that we have update privilege for all tables and columns in the Ensure that we have update privilege for all tables and columns in the
...@@ -545,9 +560,22 @@ int mysql_multi_update_prepare(THD *thd) ...@@ -545,9 +560,22 @@ int mysql_multi_update_prepare(THD *thd)
time. time.
*/ */
if (setup_tables(thd, table_list, &lex->select_lex.where) || 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); 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); DBUG_RETURN(-1);
} }
......
...@@ -1505,6 +1505,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) ...@@ -1505,6 +1505,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
List_iterator_fast<Item> it(select->item_list); List_iterator_fast<Item> it(select->item_list);
uint i= 0; uint i= 0;
bool save_set_query_id= thd->set_query_id; 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"); DBUG_ENTER("st_table_list::setup_ancestor");
if (ancestor->ancestor && if (ancestor->ancestor &&
...@@ -1542,6 +1543,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) ...@@ -1542,6 +1543,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
/* prevent look up in SELECTs tree */ /* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex; thd->lex->current_select= &thd->lex->select_lex;
thd->lex->select_lex.no_wrap_view_item= 1;
/* /*
Resolve all view items against ancestor table. Resolve all view items against ancestor table.
...@@ -1596,6 +1599,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) ...@@ -1596,6 +1599,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
} }
ok: ok:
thd->lex->select_lex.no_wrap_view_item= save_wrapper;
thd->lex->current_select= current_select_save; thd->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id; thd->set_query_id= save_set_query_id;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1607,6 +1611,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds) ...@@ -1607,6 +1611,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
thd->clear_error(); thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str); 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->lex->current_select= current_select_save;
thd->set_query_id= save_set_query_id; thd->set_query_id= save_set_query_id;
DBUG_RETURN(1); 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