mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
fixed using VIEW fields (BUG#4617)
This commit is contained in:
parent
bc98f2146d
commit
a27b1e54d5
9 changed files with 100 additions and 16 deletions
|
@ -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;
|
||||
|
|
11
sql/item.h
11
sql/item.h
|
@ -887,15 +887,15 @@ public:
|
|||
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_ref(Item **item, Item **hook,
|
||||
: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 @@ public:
|
|||
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)
|
||||
{
|
||||
table_list->next_local= save_next;
|
||||
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 @@ public:
|
|||
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))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
if (check_fields(fields))
|
||||
{
|
||||
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 (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 @@ err:
|
|||
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);
|
||||
|
|
Loading…
Reference in a new issue