fixed merged view fields names (BUG#5147)
support of merged VIEW over several tables added (WL#1809) mysql-test/r/view.result: merge of VIEW with several tables mysql-test/t/view.test: merge of VIEW with several tables sql/item.cc: renaming Item and restoring item name on cleunup() sql/item.h: renaming Item and restoring item name on cleunup() debug output added sql/item_cmpfunc.h: setup_conds() changed to support two tables lists sql/item_subselect.cc: list of table leaves used instead of local table list for name resolving sql/mysql_priv.h: setup_conds() and setup_tables() changed to support two tables lists sql/opt_sum.cc: list of table leaves used instead of local table list for name resolving sql/sp.cc: setup_tables() changed to support two tables lists sql/sql_base.cc: skip temporary tables in table finding fixed merged view fields names (BUG#5147) sql/sql_delete.cc: setup_conds() and setup_tables() changed to support two tables lists sql/sql_help.cc: setup_tables() changed to support two tables lists sql/sql_insert.cc: setup_tables() changed to support two tables lists name handling support sql/sql_lex.cc: allow view with several tables for MERGE sql/sql_lex.h: new table list sql/sql_load.cc: setup_tables() changed to support two tables lists sql/sql_olap.cc: setup_tables() changed to support two tables lists sql/sql_parse.cc: new list support sql/sql_prepare.cc: new list support sql/sql_select.cc: list of table leaves used instead of local table list for name resolving sql/sql_update.cc: setup_conds() and setup_tables() changed to support two tables lists sql/sql_view.cc: support of MERGED VIEWS with several tables sql/sql_yacc.yy: removed blanks in new code sql/table.cc: fixed setup view code support of merged VIEW over several tables added sql/table.h: fixed merged view fields names (BUG#5147)
This commit is contained in:
parent
ae70baf21c
commit
55a8c28c27
@ -877,7 +877,7 @@ insert into t1 values (1), (2), (3), (200);
|
||||
create view v1 (x) as select a from t1 where a > 1;
|
||||
create view v2 (y) as select x from v1 where x < 100;
|
||||
select * from v2;
|
||||
x
|
||||
y
|
||||
2
|
||||
3
|
||||
drop table t1;
|
||||
@ -1310,4 +1310,52 @@ a a a
|
||||
3 2 3
|
||||
3 3 3
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
drop table t1,t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
insert into t1 values (1), (2), (3);
|
||||
insert into t2 values (1), (3);
|
||||
insert into t3 values (1), (2), (4);
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
|
||||
select * from t3 left join v3 on (t3.a = v3.a);
|
||||
a a b
|
||||
1 1 1
|
||||
2 2 NULL
|
||||
4 NULL NULL
|
||||
explain extended select * from t3 left join v3 on (t3.a = v3.a);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 3
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join `test`.`t2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
|
||||
create view v1 (a) as select a from t1;
|
||||
create view v2 (a) as select a from t2;
|
||||
create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
|
||||
select * from t3 left join v4 on (t3.a = v4.a);
|
||||
a a b
|
||||
1 1 1
|
||||
2 2 NULL
|
||||
4 NULL NULL
|
||||
explain extended select * from t3 left join v4 on (t3.a = v4.a);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t3 ALL NULL NULL NULL NULL 3
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`v1` left join `test`.`v2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
|
||||
prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
|
||||
execute stmt1;
|
||||
a a b
|
||||
1 1 1
|
||||
2 2 NULL
|
||||
4 NULL NULL
|
||||
execute stmt1;
|
||||
a a b
|
||||
1 1 1
|
||||
2 2 NULL
|
||||
4 NULL NULL
|
||||
deallocate prepare stmt1;
|
||||
drop view v4,v3,v2,v1;
|
||||
drop tables t1,t2,t3;
|
||||
|
@ -1270,4 +1270,31 @@ create view v1 as select a from t1 where a > 1;
|
||||
select * from t1 left join (t2 as t, v1) on v1.a=t1.a;
|
||||
select * from t1 left join (t2 as t, t2) on t2.a=t1.a;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
drop table t1,t2;
|
||||
|
||||
#
|
||||
# merge of VIEW with several tables
|
||||
#
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
insert into t1 values (1), (2), (3);
|
||||
insert into t2 values (1), (3);
|
||||
insert into t3 values (1), (2), (4);
|
||||
# view over tables
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
|
||||
select * from t3 left join v3 on (t3.a = v3.a);
|
||||
explain extended select * from t3 left join v3 on (t3.a = v3.a);
|
||||
# view over views
|
||||
create view v1 (a) as select a from t1;
|
||||
create view v2 (a) as select a from t2;
|
||||
create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
|
||||
select * from t3 left join v4 on (t3.a = v4.a);
|
||||
explain extended select * from t3 left join v4 on (t3.a = v4.a);
|
||||
# PS with view over views
|
||||
prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
|
||||
execute stmt1;
|
||||
execute stmt1;
|
||||
deallocate prepare stmt1;
|
||||
drop view v4,v3,v2,v1;
|
||||
drop tables t1,t2,t3;
|
||||
|
34
sql/item.cc
34
sql/item.cc
@ -45,12 +45,11 @@ void item_init(void)
|
||||
}
|
||||
|
||||
Item::Item():
|
||||
name_length(0), fixed(0)
|
||||
name(0), orig_name(0), name_length(0), fixed(0)
|
||||
{
|
||||
marker= 0;
|
||||
maybe_null=null_value=with_sum_func=unsigned_flag=0;
|
||||
collation.set(default_charset(), DERIVATION_COERCIBLE);
|
||||
name= 0;
|
||||
decimals= 0; max_length= 0;
|
||||
|
||||
/* Put item in free list so that we can free all items at end */
|
||||
@ -80,6 +79,7 @@ Item::Item():
|
||||
Item::Item(THD *thd, Item *item):
|
||||
str_value(item->str_value),
|
||||
name(item->name),
|
||||
orig_name(item->orig_name),
|
||||
max_length(item->max_length),
|
||||
marker(item->marker),
|
||||
decimals(item->decimals),
|
||||
@ -110,12 +110,35 @@ void Item::print_item_w_name(String *str)
|
||||
void Item::cleanup()
|
||||
{
|
||||
DBUG_ENTER("Item::cleanup");
|
||||
DBUG_PRINT("info", ("Item: 0x%lx", this));
|
||||
DBUG_PRINT("info", ("Type: %d", (int)type()));
|
||||
DBUG_PRINT("info", ("Item: 0x%lx, Type: %d, name %s, original name %s",
|
||||
this, (int)type(), name, orig_name));
|
||||
fixed=0;
|
||||
if (orig_name)
|
||||
name= orig_name;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rename item (used for views, cleanup() return original name)
|
||||
|
||||
SYNOPSIS
|
||||
Item::rename()
|
||||
new_name new name of item;
|
||||
*/
|
||||
|
||||
void Item::rename(char *new_name)
|
||||
{
|
||||
/*
|
||||
we can compare pointers to names here, bacause if name was not changed,
|
||||
pointer will be same
|
||||
*/
|
||||
if (!orig_name && new_name != name)
|
||||
orig_name= name;
|
||||
name= new_name;
|
||||
}
|
||||
|
||||
|
||||
Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
|
||||
const char *field_name_par)
|
||||
:orig_db_name(db_name_par), orig_table_name(table_name_par),
|
||||
@ -2279,6 +2302,9 @@ void Item_ref::cleanup()
|
||||
DBUG_ENTER("Item_ref::cleanup");
|
||||
Item_ident::cleanup();
|
||||
result_field= 0;
|
||||
DBUG_PRINT("info", ("hook: 0x%lx(0x%lx) original item: 0x%lx",
|
||||
(ulong)hook_ptr, (ulong)(hook_ptr?*hook_ptr:0),
|
||||
(ulong)orig_item));
|
||||
if (hook_ptr)
|
||||
*hook_ptr= orig_item;
|
||||
DBUG_VOID_RETURN;
|
||||
|
27
sql/item.h
27
sql/item.h
@ -115,6 +115,8 @@ public:
|
||||
*/
|
||||
String str_value;
|
||||
my_string name; /* Name from select */
|
||||
/* Original item name (if it was renamed)*/
|
||||
my_string orig_name;
|
||||
Item *next;
|
||||
uint32 max_length;
|
||||
uint name_length; /* Length of name */
|
||||
@ -142,6 +144,7 @@ public:
|
||||
name=0;
|
||||
} /*lint -e1509 */
|
||||
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();
|
||||
virtual void make_field(Send_field *field);
|
||||
@ -928,15 +931,33 @@ public:
|
||||
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), result_field(0),
|
||||
ref(0), hook_ptr(hook), orig_item(original) {}
|
||||
ref(0), hook_ptr(hook), orig_item(original)
|
||||
{
|
||||
DBUG_ENTER("Item_ref::Item_ref (Item **, Item * ...) ");
|
||||
DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx",
|
||||
hook_ptr, orig_item));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
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), result_field(0),
|
||||
ref(item), hook_ptr(hook), orig_item(hook ? *hook:0) {}
|
||||
ref(item), hook_ptr(hook), orig_item(hook ? *hook:0)
|
||||
{
|
||||
DBUG_ENTER("Item_ref::Item_ref (Item **, Item ** ...) ");
|
||||
DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx",
|
||||
hook_ptr, orig_item));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
// Constructor need to process subselect with temporary tables (see Item)
|
||||
Item_ref(THD *thd, Item_ref *item, Item **hook)
|
||||
: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)
|
||||
{
|
||||
DBUG_ENTER("Item_ref::Item_ref (THD*, Item_ref, ...)");
|
||||
DBUG_PRINT("info", ("hook 0x%lx, original item: 0x%lx",
|
||||
hook_ptr, orig_item));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
enum Type type() const { return REF_ITEM; }
|
||||
bool eq(const Item *item, bool binary_cmp) const
|
||||
{ return ref && (*ref)->eq(item, binary_cmp); }
|
||||
|
@ -965,7 +965,8 @@ public:
|
||||
void update_used_tables();
|
||||
void print(String *str);
|
||||
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
|
||||
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
|
||||
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
||||
COND **conds);
|
||||
void top_level_item() { abort_on_null=1; }
|
||||
void copy_andor_arguments(THD *thd, Item_cond *item);
|
||||
bool walk(Item_processor processor, byte *arg);
|
||||
|
@ -1411,7 +1411,7 @@ void subselect_uniquesubquery_engine::exclude()
|
||||
table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
|
||||
{
|
||||
table_map map= 0;
|
||||
for(; table; table= table->next_local)
|
||||
for(; table; table= table->next_leaf)
|
||||
{
|
||||
TABLE *tbl= table->table;
|
||||
if (tbl && tbl->const_table)
|
||||
@ -1424,14 +1424,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
|
||||
table_map subselect_single_select_engine::upper_select_const_tables()
|
||||
{
|
||||
return calc_const_tables((TABLE_LIST *) select_lex->outer_select()->
|
||||
table_list.first);
|
||||
leaf_tables);
|
||||
}
|
||||
|
||||
|
||||
table_map subselect_union_engine::upper_select_const_tables()
|
||||
{
|
||||
return calc_const_tables((TABLE_LIST *) unit->outer_select()->
|
||||
table_list.first);
|
||||
return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables);
|
||||
}
|
||||
|
||||
|
||||
|
@ -764,13 +764,15 @@ bool insert_fields(THD *thd,TABLE_LIST *tables,
|
||||
const char *db_name, const char *table_name,
|
||||
List_iterator<Item> *it, bool any_privileges,
|
||||
bool allocate_view_names);
|
||||
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds);
|
||||
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
|
||||
TABLE_LIST **leaves, bool refresh_only);
|
||||
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
List<Item> *sum_func_list, uint wild_num);
|
||||
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
|
||||
List<Item> &item, bool set_query_id,
|
||||
List<Item> *sum_func_list, bool allow_sum_func);
|
||||
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
|
||||
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
|
||||
COND **conds);
|
||||
int setup_ftfuncs(SELECT_LEX* select);
|
||||
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
|
||||
void wait_for_refresh(THD *thd);
|
||||
|
@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
|
||||
|
||||
SYNOPSIS
|
||||
opt_sum_query()
|
||||
tables Tables in query
|
||||
all_fields All fields to be returned
|
||||
conds WHERE clause
|
||||
tables list of leaves of join table tree
|
||||
all_fields All fields to be returned
|
||||
conds WHERE clause
|
||||
|
||||
NOTE:
|
||||
This function is only called for queries with sum functions and no
|
||||
@ -89,7 +89,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
where_tables= conds->used_tables();
|
||||
|
||||
/* Don't replace expression on a table that is part of an outer join */
|
||||
for (TABLE_LIST *tl= tables; tl; tl= tl->next_local)
|
||||
for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
|
||||
{
|
||||
if (tl->on_expr)
|
||||
{
|
||||
@ -128,7 +128,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
{
|
||||
longlong count= 1;
|
||||
TABLE_LIST *table;
|
||||
for (table= tables; table; table= table->next_local)
|
||||
for (table= tables; table; table= table->next_leaf)
|
||||
{
|
||||
if (outer_tables || (table->table->file->table_flags() &
|
||||
HA_NOT_EXACT_COUNT))
|
||||
|
@ -551,6 +551,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
|
||||
Item *item;
|
||||
List<Item> field_list;
|
||||
struct st_used_field *used_field;
|
||||
TABLE_LIST *leaves= 0;
|
||||
st_used_field used_fields[array_elements(init_fields)];
|
||||
|
||||
memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
|
||||
@ -583,7 +584,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
|
||||
|
||||
tables is not VIEW for sure => we can pass 0 as condition
|
||||
*/
|
||||
setup_tables(thd, &tables, 0);
|
||||
setup_tables(thd, &tables, 0, &leaves, 0);
|
||||
for (used_field= &used_fields[0];
|
||||
used_field->field_name;
|
||||
used_field++)
|
||||
|
212
sql/sql_base.cc
212
sql/sql_base.cc
@ -554,10 +554,10 @@ void close_temporary_tables(THD *thd)
|
||||
|
||||
SYNOPSIS
|
||||
find_table_in_list()
|
||||
table Pointer to table list
|
||||
table Pointer to table list
|
||||
offset Offset to which list in table structure to use
|
||||
db_name Data base name
|
||||
table_name Table name
|
||||
db_name Data base name
|
||||
table_name Table name
|
||||
|
||||
NOTES:
|
||||
This is called by find_table_in_local_list() and
|
||||
@ -577,13 +577,14 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_cache_key, db_name) &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_name, table_name)))
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_cache_key, db_name) &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -591,11 +592,12 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name)))
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2005,15 +2007,18 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
bool allow_rowid,
|
||||
uint *cached_field_index_ptr)
|
||||
{
|
||||
DBUG_ENTER("find_field_in_table");
|
||||
DBUG_PRINT("enter", ("table:%s name: %s item name %s, ref 0x%lx",
|
||||
table_list->alias, name, item_name, (ulong)ref));
|
||||
Field *fld;
|
||||
if (table_list->field_translation)
|
||||
{
|
||||
DBUG_ASSERT(ref != 0 && table_list->view != 0);
|
||||
uint num= table_list->view->select_lex.item_list.elements;
|
||||
Item **trans= table_list->field_translation;
|
||||
Field_translator *trans= table_list->field_translation;
|
||||
for (uint i= 0; i < num; i ++)
|
||||
{
|
||||
if (strcmp(trans[i]->name, name) == 0)
|
||||
if (strcmp(trans[i].name, name) == 0)
|
||||
{
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (check_grants_view &&
|
||||
@ -2021,22 +2026,22 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
table_list->view_db.str,
|
||||
table_list->view_name.str,
|
||||
name, length))
|
||||
return WRONG_GRANT;
|
||||
DBUG_RETURN(WRONG_GRANT);
|
||||
#endif
|
||||
if (thd->lex->current_select->no_wrap_view_item)
|
||||
*ref= trans[i];
|
||||
*ref= trans[i].item;
|
||||
else
|
||||
{
|
||||
*ref= new Item_ref(trans + i, ref, table_list->view_name.str,
|
||||
*ref= new Item_ref(&trans[i].item, ref, table_list->view_name.str,
|
||||
item_name);
|
||||
/* 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;
|
||||
DBUG_RETURN((Field*) view_ref_found);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
fld= find_field_in_real_table(thd, table_list->table, name, length,
|
||||
check_grants_table, allow_rowid,
|
||||
@ -2050,10 +2055,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
table_list->view_name.str,
|
||||
name, length))
|
||||
{
|
||||
return WRONG_GRANT;
|
||||
DBUG_RETURN(WRONG_GRANT);
|
||||
}
|
||||
#endif
|
||||
return fld;
|
||||
DBUG_RETURN(fld);
|
||||
}
|
||||
|
||||
|
||||
@ -2182,17 +2187,33 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
field makes some prepared query ambiguous and so erronous, but we
|
||||
accept this trade off.
|
||||
*/
|
||||
found= find_field_in_real_table(thd, item->cached_table->table,
|
||||
name, length,
|
||||
test(item->cached_table->
|
||||
table->grant.want_privilege) &&
|
||||
check_privileges,
|
||||
1, &(item->cached_field_index));
|
||||
if (item->cached_table->table)
|
||||
{
|
||||
found= find_field_in_real_table(thd, item->cached_table->table,
|
||||
name, length,
|
||||
test(item->cached_table->
|
||||
table->grant.want_privilege) &&
|
||||
check_privileges,
|
||||
1, &(item->cached_field_index));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
TABLE_LIST *table= item->cached_table;
|
||||
Field *find= find_field_in_table(thd, table, name, item->name, length,
|
||||
ref,
|
||||
(table->table &&
|
||||
test(table->table->grant.
|
||||
want_privilege) &&
|
||||
check_privileges),
|
||||
(test(table->grant.want_privilege) &&
|
||||
check_privileges),
|
||||
1, &(item->cached_field_index));
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
if (found == WRONG_GRANT)
|
||||
return (Field*) 0;
|
||||
return (Field*) 0;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
@ -2220,7 +2241,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
found_table=1;
|
||||
Field *find= find_field_in_table(thd, tables, name, item->name,
|
||||
length, ref,
|
||||
(test(tables->table->grant.
|
||||
(tables->table &&
|
||||
test(tables->table->grant.
|
||||
want_privilege) &&
|
||||
check_privileges),
|
||||
(test(tables->grant.want_privilege) &&
|
||||
@ -2284,7 +2306,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
|
||||
Field *field= find_field_in_table(thd, tables, name, item->name,
|
||||
length, ref,
|
||||
(test(tables->table->grant.
|
||||
(tables->table &&
|
||||
test(tables->table->grant.
|
||||
want_privilege) &&
|
||||
check_privileges),
|
||||
(test(tables->grant.want_privilege) &&
|
||||
@ -2597,7 +2620,6 @@ 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)
|
||||
@ -2611,14 +2633,46 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
make list of leaves of join table tree
|
||||
|
||||
SYNOPSIS
|
||||
make_leaves_list()
|
||||
list pointer to pointer on list first element
|
||||
tables table list
|
||||
|
||||
RETURN pointer on pointer to next_leaf of last element
|
||||
*/
|
||||
|
||||
TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
|
||||
{
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
{
|
||||
if (table->view && !table->table)
|
||||
{
|
||||
/* it is for multi table views only, check it */
|
||||
DBUG_ASSERT(table->ancestor->next_local);
|
||||
list= make_leaves_list(list, table->ancestor);
|
||||
}
|
||||
else
|
||||
{
|
||||
*list= table;
|
||||
list= &table->next_leaf;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
prepare tables
|
||||
|
||||
SYNOPSIS
|
||||
setup_tables()
|
||||
thd - thread handler
|
||||
tables - tables list
|
||||
conds - condition of current SELECT (can be changed by VIEW)
|
||||
thd - thread handler
|
||||
tables - tables list
|
||||
conds - condition of current SELECT (can be changed by VIEW)
|
||||
leaves - list of join table leaves list
|
||||
refresh - it is onle refresh for subquery
|
||||
|
||||
RETURN
|
||||
0 ok; In this case *map will includes the choosed index
|
||||
@ -2635,16 +2689,23 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
if tables do not contain VIEWs it is OK to pass 0 as conds
|
||||
*/
|
||||
|
||||
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds)
|
||||
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
|
||||
TABLE_LIST **leaves, bool refresh)
|
||||
{
|
||||
DBUG_ENTER("setup_tables");
|
||||
if (!tables || tables->setup_is_done)
|
||||
DBUG_RETURN(0);
|
||||
tables->setup_is_done= 1;
|
||||
|
||||
if (!(*leaves))
|
||||
{
|
||||
make_leaves_list(leaves, tables);
|
||||
}
|
||||
|
||||
uint tablenr=0;
|
||||
for (TABLE_LIST *table_list= tables;
|
||||
for (TABLE_LIST *table_list= *leaves;
|
||||
table_list;
|
||||
table_list= table_list->next_local, tablenr++)
|
||||
table_list= table_list->next_leaf, tablenr++)
|
||||
{
|
||||
TABLE *table= table_list->table;
|
||||
setup_table_map(table, table_list, tablenr);
|
||||
@ -2666,14 +2727,22 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds)
|
||||
table->keys_in_use_for_query.subtract(map);
|
||||
}
|
||||
table->used_keys.intersect(table->keys_in_use_for_query);
|
||||
if (table_list->ancestor && table_list->setup_ancestor(thd, conds))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (tablenr > MAX_TABLES)
|
||||
{
|
||||
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (!refresh)
|
||||
{
|
||||
for (TABLE_LIST *table_list= tables;
|
||||
table_list;
|
||||
table_list= table_list->next_local)
|
||||
{
|
||||
if (table_list->ancestor && table_list->setup_ancestor(thd, conds))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -2776,9 +2845,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
tables->alias) &&
|
||||
(!db_name || !strcmp(tables->db,db_name))))
|
||||
{
|
||||
bool view;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/* Ensure that we have access right to all columns */
|
||||
if (!(table->grant.privilege & SELECT_ACL) && !any_privileges)
|
||||
if (!((table && (table->grant.privilege & SELECT_ACL) ||
|
||||
tables->view && (tables->grant.privilege & SELECT_ACL))) &&
|
||||
!any_privileges)
|
||||
{
|
||||
if (tables->view)
|
||||
{
|
||||
@ -2791,6 +2863,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(table != 0);
|
||||
table_iter.set(tables);
|
||||
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
|
||||
table->table_cache_key, table->real_name,
|
||||
@ -2799,8 +2872,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (table)
|
||||
thd->used_tables|= table->map;
|
||||
else
|
||||
{
|
||||
view_iter.set(tables);
|
||||
for (; !view_iter.end_of_fields(); view_iter.next())
|
||||
{
|
||||
thd->used_tables|= view_iter.item(thd)->used_tables();
|
||||
}
|
||||
}
|
||||
natural_join_table= 0;
|
||||
thd->used_tables|= table->map;
|
||||
last= embedded= tables;
|
||||
|
||||
while ((embedding= embedded->embedding) &&
|
||||
@ -2827,9 +2909,15 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
natural_join_table= embedding;
|
||||
}
|
||||
if (tables->field_translation)
|
||||
{
|
||||
iterator= &view_iter;
|
||||
view= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iterator= &table_iter;
|
||||
view= 0;
|
||||
}
|
||||
iterator->set(tables);
|
||||
|
||||
for (; !iterator->end_of_fields(); iterator->next())
|
||||
@ -2849,6 +2937,11 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
(void) it->replace(item); // Replace '*'
|
||||
else
|
||||
it->after(item);
|
||||
if (view && !thd->lex->current_select->no_wrap_view_item)
|
||||
{
|
||||
item= new Item_ref(it->ref(), NULL, tables->view_name.str,
|
||||
field_name);
|
||||
}
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (any_privileges)
|
||||
{
|
||||
@ -2914,8 +3007,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
|
||||
}
|
||||
/* All fields are used */
|
||||
table->used_fields=table->fields;
|
||||
/*
|
||||
All fields are used in case if usual tables (in case of view used
|
||||
fields merked in setu_tables during fix_fields of view columns
|
||||
*/
|
||||
if (table)
|
||||
table->used_fields=table->fields;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
@ -2933,10 +3030,16 @@ err:
|
||||
|
||||
|
||||
/*
|
||||
** Fix all conditions and outer join expressions
|
||||
Fix all conditions and outer join expressions
|
||||
|
||||
SYNOPSIS
|
||||
setup_conds()
|
||||
thd thread handler
|
||||
tables list of tables for name resolving
|
||||
leaves list of leaves of join table tree
|
||||
*/
|
||||
|
||||
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
|
||||
{
|
||||
table_map not_null_tables= 0;
|
||||
SELECT_LEX *select_lex= thd->lex->current_select;
|
||||
@ -2960,7 +3063,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
}
|
||||
|
||||
/* Check if we are using outer joins */
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
for (TABLE_LIST *table= leaves; table; table= table->next_leaf)
|
||||
{
|
||||
TABLE_LIST *embedded;
|
||||
TABLE_LIST *embedding= table;
|
||||
@ -3024,8 +3127,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
Field_iterator_view view_iter;
|
||||
Field_iterator *iterator;
|
||||
Field *t1_field, *t2_field;
|
||||
Item *item_t2;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
Item *item_t2= 0;
|
||||
Item_cond_and *cond_and= new Item_cond_and();
|
||||
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
@ -3061,6 +3164,13 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
t2_field->query_id= thd->query_id;
|
||||
t2->used_keys.intersect(t2_field->part_of_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(t2_field == view_ref_found &&
|
||||
item_t2->type() == Item::REF_ITEM);
|
||||
/* remove hooking to stack variable */
|
||||
((Item_ref*) item_t2)->hook_ptr= 0;
|
||||
}
|
||||
if ((t1_field= iterator->field()))
|
||||
{
|
||||
/* Mark field used for table cache */
|
||||
|
@ -284,8 +284,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
|
||||
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||
DBUG_ENTER("mysql_prepare_delete");
|
||||
|
||||
if (setup_tables(thd, table_list, conds) ||
|
||||
setup_conds(thd, table_list, conds) ||
|
||||
if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
|
||||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
|
||||
setup_ftfuncs(select_lex))
|
||||
DBUG_RETURN(-1);
|
||||
if (!table_list->updatable || check_key_in_view(thd, table_list))
|
||||
@ -341,7 +341,8 @@ int mysql_multi_delete_prepare(THD *thd)
|
||||
|
||||
lex->query_tables also point on local list of DELETE SELECT_LEX
|
||||
*/
|
||||
if (setup_tables(thd, lex->query_tables, &lex->select_lex.where))
|
||||
if (setup_tables(thd, lex->query_tables, &lex->select_lex.where,
|
||||
&lex->select_lex.leaf_tables, 0))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/* Fix tables-to-be-deleted-from list to point at opened tables */
|
||||
|
@ -619,6 +619,7 @@ int mysqld_help(THD *thd, const char *mask)
|
||||
st_find_field used_fields[array_elements(init_used_fields)];
|
||||
DBUG_ENTER("mysqld_help");
|
||||
|
||||
TABLE_LIST *leaves= 0;
|
||||
TABLE_LIST tables[4];
|
||||
bzero((gptr)tables,sizeof(tables));
|
||||
tables[0].alias= tables[0].real_name= (char*) "help_topic";
|
||||
@ -647,7 +648,7 @@ int mysqld_help(THD *thd, const char *mask)
|
||||
|
||||
tables do not contain VIEWs => we can pass 0 as conds
|
||||
*/
|
||||
setup_tables(thd, tables, 0);
|
||||
setup_tables(thd, tables, 0, &leaves, 0);
|
||||
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
|
||||
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
|
||||
{
|
||||
|
@ -476,8 +476,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
uint num= view->view->select_lex.item_list.elements;
|
||||
TABLE *table= view->table;
|
||||
Item **trans_start= view->field_translation, **trans_end=trans_start+num;
|
||||
Item **trans;
|
||||
Field_translator *trans_start= view->field_translation,
|
||||
*trans_end= trans_start + num;
|
||||
Field_translator *trans;
|
||||
Field **field_ptr= table->field;
|
||||
ulong other_query_id= query_id - 1;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
@ -490,9 +491,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
Item_field *field;
|
||||
/* simple SELECT list entry (field without expression) */
|
||||
if ((*trans)->type() != Item::FIELD_ITEM)
|
||||
if (trans->item->type() != Item::FIELD_ITEM)
|
||||
DBUG_RETURN(TRUE);
|
||||
field= (Item_field *)(*trans);
|
||||
field= (Item_field *)trans->item;
|
||||
if (field->field->unireg_check == Field::NEXT_NUMBER)
|
||||
view->contain_auto_increment= 1;
|
||||
/* prepare unique test */
|
||||
@ -502,7 +503,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
for (trans= trans_start; trans != trans_end; trans++)
|
||||
{
|
||||
/* Thanks to test above, we know that all columns are of type Item_field */
|
||||
Item_field *field= (Item_field *)(*trans);
|
||||
Item_field *field= (Item_field *)trans->item;
|
||||
if (field->field->query_id == query_id)
|
||||
DBUG_RETURN(TRUE);
|
||||
field->field->query_id= query_id;
|
||||
@ -521,7 +522,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
if (trans == trans_end)
|
||||
DBUG_RETURN(TRUE); // Field was not part of view
|
||||
if (((Item_field *)(*trans))->field == *field_ptr)
|
||||
if (((Item_field *)trans->item)->field == *field_ptr)
|
||||
break; // ok
|
||||
}
|
||||
}
|
||||
@ -551,7 +552,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
DBUG_ENTER("mysql_prepare_insert_check_table");
|
||||
|
||||
if (setup_tables(thd, table_list, where))
|
||||
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
|
||||
0))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (insert_into_view && !fields.elements)
|
||||
@ -1616,6 +1618,10 @@ int mysql_insert_select_prepare(THD *thd)
|
||||
lex->field_list,
|
||||
&lex->select_lex.where))
|
||||
DBUG_RETURN(-1);
|
||||
/* exclude first table from leaf tables list, because it belong to INSERT */
|
||||
DBUG_ASSERT(lex->select_lex.leaf_tables);
|
||||
lex->leaf_tables_insert= lex->select_lex.leaf_tables;
|
||||
lex->select_lex.leaf_tables= lex->select_lex.leaf_tables->next_leaf;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -1006,7 +1006,7 @@ void st_select_lex::init_query()
|
||||
table_list.empty();
|
||||
top_join_list.empty();
|
||||
join_list= &top_join_list;
|
||||
embedding= 0;
|
||||
embedding= leaf_tables= 0;
|
||||
item_list.empty();
|
||||
join= 0;
|
||||
where= prep_where= 0;
|
||||
@ -1564,7 +1564,7 @@ bool st_lex::can_be_merged()
|
||||
select_lex.group_list.elements == 0 &&
|
||||
select_lex.having == 0 &&
|
||||
select_lex.with_sum_func == 0 &&
|
||||
select_lex.table_list.elements == 1 &&
|
||||
select_lex.table_list.elements >= 1 &&
|
||||
!(select_lex.options & SELECT_DISTINCT) &&
|
||||
select_lex.select_limit == HA_POS_ERROR);
|
||||
}
|
||||
|
@ -432,6 +432,7 @@ public:
|
||||
List<TABLE_LIST> top_join_list; /* join list of the top level */
|
||||
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
|
||||
TABLE_LIST *embedding; /* table embedding to the above list */
|
||||
TABLE_LIST *leaf_tables; /* list of leaves in join table tree */
|
||||
const char *type; /* type of select for EXPLAIN */
|
||||
|
||||
SQL_LIST order_list; /* ORDER clause */
|
||||
@ -650,6 +651,8 @@ typedef struct st_lex
|
||||
*/
|
||||
TABLE_LIST **query_tables_last;
|
||||
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
|
||||
/* store original leaf_tables for INSERT SELECT and PS/SP */
|
||||
TABLE_LIST *leaf_tables_insert;
|
||||
|
||||
List<key_part_spec> col_list;
|
||||
List<key_part_spec> ref_list;
|
||||
|
@ -138,7 +138,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
thd->dupp_field=0;
|
||||
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
|
||||
Item *unused_conds= 0;
|
||||
if (setup_tables(thd, table_list, &unused_conds) ||
|
||||
TABLE_LIST *leaves= 0;
|
||||
if (setup_tables(thd, table_list, &unused_conds, &leaves, 0) ||
|
||||
setup_fields(thd, 0, table_list, fields, 1, 0, 0))
|
||||
DBUG_RETURN(-1);
|
||||
if (thd->dupp_field)
|
||||
|
@ -153,7 +153,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
|
||||
|
||||
|
||||
if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first
|
||||
&select_lex->where) ||
|
||||
&select_lex->where, &select_lex->leaf_tables, 0) ||
|
||||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
|
||||
select_lex->item_list, 1, &all_fields,1) ||
|
||||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
|
||||
|
@ -4344,7 +4344,7 @@ mysql_init_query(THD *thd, uchar *buf, uint length, bool lexonly)
|
||||
lex->found_colon= 0;
|
||||
lex->safe_to_cache_query= 1;
|
||||
lex->time_zone_tables_used= 0;
|
||||
lex->proc_table= lex->query_tables= 0;
|
||||
lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0;
|
||||
lex->query_tables_last= &lex->query_tables;
|
||||
lex->variables_used= 0;
|
||||
lex->select_lex.parent_lex= lex;
|
||||
|
@ -1717,8 +1717,15 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
|
||||
were closed in the end of previous prepare or execute call.
|
||||
*/
|
||||
tables->table= 0;
|
||||
if (tables->nested_join)
|
||||
tables->nested_join->counter= 0;
|
||||
}
|
||||
lex->current_select= &lex->select_lex;
|
||||
|
||||
/* restore original list used in INSERT ... SELECT */
|
||||
if (lex->leaf_tables_insert)
|
||||
lex->select_lex.leaf_tables= lex->leaf_tables_insert;
|
||||
|
||||
if (lex->result)
|
||||
lex->result->cleanup();
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ const key_map key_map_empty(0);
|
||||
const key_map key_map_full(~0);
|
||||
|
||||
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
|
||||
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
|
||||
DYNAMIC_ARRAY *keyuse);
|
||||
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
||||
JOIN_TAB *join_tab,
|
||||
@ -243,6 +243,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
||||
*/
|
||||
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
|
||||
TABLE_LIST *tables,
|
||||
TABLE_LIST *leaves,
|
||||
List<Item> &fields,
|
||||
List<Item> &all_fields,
|
||||
COND **conds,
|
||||
@ -255,7 +256,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
|
||||
|
||||
save_allow_sum_func= thd->allow_sum_func;
|
||||
thd->allow_sum_func= 0;
|
||||
res= (setup_conds(thd, tables, conds) ||
|
||||
res= (setup_conds(thd, tables, leaves, conds) ||
|
||||
setup_order(thd, ref_pointer_array, tables, fields, all_fields,
|
||||
order) ||
|
||||
setup_group(thd, ref_pointer_array, tables, fields, all_fields,
|
||||
@ -302,13 +303,14 @@ JOIN::prepare(Item ***rref_pointer_array,
|
||||
|
||||
/* Check that all tables, fields, conds and order are ok */
|
||||
|
||||
if (setup_tables(thd, tables_list, &conds) ||
|
||||
if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 0) ||
|
||||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
|
||||
select_lex->setup_ref_array(thd, og_num) ||
|
||||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
|
||||
&all_fields, 1) ||
|
||||
setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
|
||||
all_fields, &conds, order, group_list,
|
||||
setup_without_group(thd, (*rref_pointer_array), tables_list,
|
||||
select_lex->leaf_tables, fields_list,
|
||||
all_fields, &conds, order, group_list,
|
||||
&hidden_group_fields))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
|
||||
@ -375,7 +377,9 @@ JOIN::prepare(Item ***rref_pointer_array,
|
||||
}
|
||||
}
|
||||
TABLE_LIST *table_ptr;
|
||||
for (table_ptr= tables_list; table_ptr; table_ptr= table_ptr->next_local)
|
||||
for (table_ptr= select_lex->leaf_tables;
|
||||
table_ptr;
|
||||
table_ptr= table_ptr->next_leaf)
|
||||
tables++;
|
||||
}
|
||||
{
|
||||
@ -552,7 +556,7 @@ JOIN::optimize()
|
||||
opt_sum_query() returns -1 if no rows match to the WHERE conditions,
|
||||
or 1 if all items were resolved, or 0, or an error number HA_ERR_...
|
||||
*/
|
||||
if ((res=opt_sum_query(tables_list, all_fields, conds)))
|
||||
if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
|
||||
{
|
||||
if (res > 1)
|
||||
{
|
||||
@ -578,11 +582,11 @@ JOIN::optimize()
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
error= -1; // Error is sent to client
|
||||
sort_by_table= get_sort_by_table(order, group_list, tables_list);
|
||||
sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables);
|
||||
|
||||
/* Calculate how to do the join */
|
||||
thd->proc_info= "statistics";
|
||||
if (make_join_statistics(this, tables_list, conds, &keyuse) ||
|
||||
if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
|
||||
thd->is_fatal_error)
|
||||
{
|
||||
DBUG_PRINT("error",("Error: make_join_statistics() failed"));
|
||||
@ -1016,7 +1020,7 @@ JOIN::reinit()
|
||||
if (tables_list)
|
||||
{
|
||||
tables_list->setup_is_done= 0;
|
||||
if (setup_tables(thd, tables_list, &conds))
|
||||
if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 1))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@ -1121,7 +1125,7 @@ JOIN::exec()
|
||||
|
||||
if (zero_result_cause)
|
||||
{
|
||||
(void) return_zero_rows(this, result, tables_list, fields_list,
|
||||
(void) return_zero_rows(this, result, select_lex->leaf_tables, fields_list,
|
||||
send_row_on_empty_set(),
|
||||
select_options,
|
||||
zero_result_cause,
|
||||
@ -2030,7 +2034,7 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
*/
|
||||
|
||||
static bool
|
||||
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
||||
DYNAMIC_ARRAY *keyuse_array)
|
||||
{
|
||||
int error;
|
||||
@ -2060,7 +2064,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
|
||||
for (s= stat, i= 0;
|
||||
tables;
|
||||
s++, tables= tables->next_local, i++)
|
||||
s++, tables= tables->next_leaf, i++)
|
||||
{
|
||||
TABLE_LIST *embedding= tables->embedding;
|
||||
stat_vector[i]=s;
|
||||
@ -4836,6 +4840,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
|
||||
static void
|
||||
make_outerjoin_info(JOIN *join)
|
||||
{
|
||||
DBUG_ENTER("make_outerjoin_info");
|
||||
for (uint i=join->const_tables ; i < join->tables ; i++)
|
||||
{
|
||||
JOIN_TAB *tab=join->join_tab+i;
|
||||
@ -4877,6 +4882,7 @@ make_outerjoin_info(JOIN *join)
|
||||
nested_join->first_nested->last_inner= tab;
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -4952,7 +4958,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
||||
in the ON part of an OUTER JOIN. In this case we want the code
|
||||
below to check if we should use 'quick' instead.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Item_int"));
|
||||
tmp= new Item_int((longlong) 1,1); // Always true
|
||||
DBUG_PRINT("info", ("Item_int 0x%lx", (ulong)tmp));
|
||||
}
|
||||
|
||||
}
|
||||
@ -5122,13 +5130,18 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
|
||||
Now add the guard turning the predicate off for
|
||||
the null complemented row.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Item_func_trig_cond"));
|
||||
tmp= new Item_func_trig_cond(tmp,
|
||||
&first_inner_tab->not_null_compl);
|
||||
DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
|
||||
if (tmp)
|
||||
tmp->quick_fix_field();
|
||||
/* Add the predicate to other pushed down predicates */
|
||||
DBUG_PRINT("info", ("Item_cond_and"));
|
||||
cond_tab->select_cond= !cond_tab->select_cond ? tmp :
|
||||
new Item_cond_and(cond_tab->select_cond,tmp);
|
||||
DBUG_PRINT("info", ("Item_cond_and 0x%lx",
|
||||
(ulong)cond_tab->select_cond));
|
||||
if (!cond_tab->select_cond)
|
||||
DBUG_RETURN(1);
|
||||
cond_tab->select_cond->quick_fix_field();
|
||||
@ -5674,7 +5687,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
|
||||
|
||||
if (send_row)
|
||||
{
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_leaf)
|
||||
mark_as_null_row(table->table); // All fields are NULL
|
||||
if (having && having->val_int() == 0)
|
||||
send_row=0;
|
||||
@ -7702,6 +7715,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
|
||||
join->thd->send_kill_message();
|
||||
return -2; /* purecov: inspected */
|
||||
}
|
||||
DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond));
|
||||
if (!select_cond || select_cond->val_int())
|
||||
{
|
||||
/*
|
||||
@ -10376,7 +10390,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
|
||||
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
for (; !(map & tables->table->map); tables= tables->next_local);
|
||||
for (; !(map & tables->table->map); tables= tables->next_leaf);
|
||||
if (map != tables->table->map)
|
||||
DBUG_RETURN(0); // More than one table
|
||||
DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
|
||||
|
@ -497,8 +497,8 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
tables.table= table;
|
||||
tables.alias= table_list->alias;
|
||||
|
||||
if (setup_tables(thd, table_list, conds) ||
|
||||
setup_conds(thd, table_list, conds) ||
|
||||
if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
|
||||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
|
||||
select_lex->setup_ref_array(thd, order_num) ||
|
||||
setup_order(thd, select_lex->ref_pointer_array,
|
||||
table_list, all_fields, all_fields, order) ||
|
||||
@ -542,25 +542,31 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
TABLE_LIST *table_list= lex->query_tables;
|
||||
List<Item> *fields= &lex->select_lex.item_list;
|
||||
TABLE_LIST *tl;
|
||||
TABLE_LIST *leaves;
|
||||
table_map tables_for_update= 0, readonly_tables= 0;
|
||||
int res;
|
||||
bool update_view= 0;
|
||||
DBUG_ENTER("mysql_multi_update_prepare");
|
||||
|
||||
if (setup_tables(thd, table_list, &lex->select_lex.where,
|
||||
&lex->select_lex.leaf_tables, 0))
|
||||
DBUG_RETURN(-1);
|
||||
/*
|
||||
Ensure that we have update privilege for all tables and columns in the
|
||||
SET part
|
||||
*/
|
||||
for (tl= table_list; tl; tl= tl->next_local)
|
||||
for (tl= (leaves= lex->select_lex.leaf_tables); tl; tl= tl->next_leaf)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
/*
|
||||
Update of derived tables is checked later
|
||||
We don't check privileges here, becasue then we would get error
|
||||
"UPDATE command denided .. for column N" instead of
|
||||
"Target table ... is not updatable"
|
||||
*/
|
||||
if (!tl->derived)
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
TABLE *table= tl->table;
|
||||
TABLE_LIST *tlist;
|
||||
if (!(tlist= tl->belong_to_view?tl->belong_to_view:tl)->derived)
|
||||
tlist->grant.want_privilege= table->grant.want_privilege=
|
||||
(UPDATE_ACL & ~table->grant.privilege);
|
||||
}
|
||||
|
||||
@ -568,14 +574,13 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
setup_tables() need for VIEWs. JOIN::prepare() will not do it second
|
||||
time.
|
||||
*/
|
||||
if (setup_tables(thd, table_list, &lex->select_lex.where) ||
|
||||
(thd->lex->select_lex.no_wrap_view_item= 1,
|
||||
if ((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);
|
||||
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
for (tl= table_list; tl; tl= tl->next_local)
|
||||
{
|
||||
if (tl->view)
|
||||
{
|
||||
@ -602,25 +607,26 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
/*
|
||||
Count tables and setup timestamp handling
|
||||
*/
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
for (tl= leaves; tl; tl= tl->next_leaf)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
TABLE_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl;
|
||||
|
||||
/* We only need SELECT privilege for columns in the values list */
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
tlist->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
// Only set timestamp column if this is not modified
|
||||
if (table->timestamp_field &&
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
table->timestamp_on_update_now= 0;
|
||||
|
||||
if (!tl->updatable || check_key_in_view(thd, tl))
|
||||
if (!tlist->updatable || check_key_in_view(thd, tl))
|
||||
readonly_tables|= table->map;
|
||||
}
|
||||
if (tables_for_update & readonly_tables)
|
||||
{
|
||||
// find readonly table/view which cause error
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
for (tl= leaves; tl; tl= tl->next_local)
|
||||
{
|
||||
if ((readonly_tables & tl->table->map) &&
|
||||
(tables_for_update & tl->table->map))
|
||||
@ -726,6 +732,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
update.empty();
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
/* TODO: add support of view of join support */
|
||||
TABLE *table=table_ref->table;
|
||||
if (tables_to_update & table->map)
|
||||
{
|
||||
@ -796,7 +803,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
if (!(tables_to_update & table->map) &&
|
||||
find_table_in_local_list(update_tables, table_ref->db,
|
||||
table_ref->real_name))
|
||||
table->no_cache= 1; // Disable row cache
|
||||
|
@ -465,15 +465,20 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
if ((view->updatable_view= (can_be_merged &&
|
||||
view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
|
||||
{
|
||||
// TODO: change here when we will support UNIONs
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
if (thd->lex->select_lex.table_list.elements > 1)
|
||||
view->updatable_view= 0;
|
||||
else
|
||||
{
|
||||
if (tbl->view && !tbl->updatable_view)
|
||||
// TODO: change here when we will support UNIONs
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
if (tbl->view && !tbl->updatable_view)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -516,6 +521,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
SELECT_LEX *end;
|
||||
THD *thd= current_thd;
|
||||
LEX *old_lex= thd->lex, *lex;
|
||||
SELECT_LEX *view_select;
|
||||
int res= 0;
|
||||
|
||||
/*
|
||||
@ -558,7 +564,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
*/
|
||||
table->view= lex= thd->lex= (LEX*) new(&thd->mem_root) st_lex_local;
|
||||
mysql_init_query(thd, (uchar*)table->query.str, table->query.length, TRUE);
|
||||
lex->select_lex.select_number= ++thd->select_number;
|
||||
view_select= &lex->select_lex;
|
||||
view_select->select_number= ++thd->select_number;
|
||||
old_lex->derived_tables|= DERIVED_VIEW;
|
||||
{
|
||||
ulong options= thd->options;
|
||||
@ -601,6 +608,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
table);
|
||||
TABLE_LIST *view_tables= lex->query_tables;
|
||||
TABLE_LIST *view_tables_tail= 0;
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
if (lex->spfuns.records)
|
||||
{
|
||||
@ -655,7 +663,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
|
||||
lex->safe_to_cache_query);
|
||||
/* move SQL_CACHE to whole query */
|
||||
if (lex->select_lex.options & OPTION_TO_QUERY_CACHE)
|
||||
if (view_select->options & OPTION_TO_QUERY_CACHE)
|
||||
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
|
||||
|
||||
/*
|
||||
@ -704,20 +712,51 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
table->updatable= (table->updatable_view != 0);
|
||||
|
||||
table->ancestor= view_tables;
|
||||
|
||||
/*
|
||||
next table should include SELECT_LEX under this table SELECT_LEX
|
||||
|
||||
TODO: ehere should be loop for multi tables substitution
|
||||
*/
|
||||
table->ancestor->select_lex= table->select_lex;
|
||||
|
||||
/*
|
||||
move lock type (TODO: should we issue error in case of TMPTABLE
|
||||
algorithm and non-read locking)?
|
||||
Process upper level tables of view. As far as we do noy suport union
|
||||
here we can go through local tables of view most upper SELECT
|
||||
*/
|
||||
view_tables->lock_type= table->lock_type;
|
||||
for(tbl= (TABLE_LIST*)view_select->table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
/*
|
||||
move lock type (TODO: should we issue error in case of TMPTABLE
|
||||
algorithm and non-read locking)?
|
||||
*/
|
||||
tbl->lock_type= table->lock_type;
|
||||
}
|
||||
|
||||
/* multi table view */
|
||||
if (view_tables->next_local)
|
||||
{
|
||||
table->updatable= 0;
|
||||
/* make nested join structure for view tables */
|
||||
NESTED_JOIN *nested_join;
|
||||
if (!(nested_join= table->nested_join=
|
||||
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
||||
goto err;
|
||||
nested_join->join_list= view_select->top_join_list;
|
||||
|
||||
/* re-nest tables of VIEW */
|
||||
{
|
||||
List_iterator_fast<TABLE_LIST> ti(nested_join->join_list);
|
||||
while(tbl= ti++)
|
||||
{
|
||||
tbl->join_list= &nested_join->join_list;
|
||||
tbl->embedding= table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Store WHERE clause for postprocessing in setup_ancestor */
|
||||
table->where= lex->select_lex.where;
|
||||
table->where= view_select->where;
|
||||
|
||||
/*
|
||||
This SELECT_LEX will be linked in global SELECT_LEX list
|
||||
@ -730,12 +769,12 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
|
||||
table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
|
||||
DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
|
||||
lex->select_lex.linkage= DERIVED_TABLE_TYPE;
|
||||
view_select->linkage= DERIVED_TABLE_TYPE;
|
||||
table->updatable= 0;
|
||||
|
||||
/* SELECT tree link */
|
||||
lex->unit.include_down(table->select_lex);
|
||||
lex->unit.slave= &lex->select_lex; // fix include_down initialisation
|
||||
lex->unit.slave= view_select; // fix include_down initialisation
|
||||
|
||||
table->derived= &lex->unit;
|
||||
}
|
||||
@ -746,7 +785,7 @@ ok:
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
/* global SELECT list linking */
|
||||
end= &lex->select_lex; // primary SELECT_LEX is always last
|
||||
end= view_select; // primary SELECT_LEX is always last
|
||||
end->link_next= old_lex->all_selects_list;
|
||||
old_lex->all_selects_list->link_prev= &end->link_next;
|
||||
old_lex->all_selects_list= lex->all_selects_list;
|
||||
@ -875,7 +914,7 @@ frm_type_enum mysql_frm_type(char *path)
|
||||
bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
{
|
||||
TABLE *table;
|
||||
Item **trans;
|
||||
Field_translator *trans;
|
||||
KEY *key_info, *key_info_end;
|
||||
uint i, elements_in_view;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
@ -903,8 +942,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
uint k;
|
||||
for (k= 0; k < elements_in_view; k++)
|
||||
{
|
||||
if (trans[k]->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[k])->field == key_part->field)
|
||||
if (trans[k].item->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[k].item)->field == key_part->field)
|
||||
break;
|
||||
}
|
||||
if (k == elements_in_view)
|
||||
@ -923,8 +962,8 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
{
|
||||
for (i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
if (trans[i]->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[i])->field == *field_ptr)
|
||||
if (trans[i].item->type() == Item::FIELD_ITEM &&
|
||||
((Item_field *)trans[i].item)->field == *field_ptr)
|
||||
break;
|
||||
}
|
||||
if (i == elements_in_view) // If field didn't exists
|
||||
@ -968,7 +1007,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
void insert_view_fields(List<Item> *list, TABLE_LIST *view)
|
||||
{
|
||||
uint elements_in_view= view->view->select_lex.item_list.elements;
|
||||
Item **trans;
|
||||
Field_translator *trans;
|
||||
DBUG_ENTER("insert_view_fields");
|
||||
|
||||
if (!(trans= view->field_translation))
|
||||
@ -976,8 +1015,8 @@ void insert_view_fields(List<Item> *list, TABLE_LIST *view)
|
||||
|
||||
for (uint i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
if (trans[i]->type() == Item::FIELD_ITEM)
|
||||
list->push_back(trans[i]);
|
||||
if (trans[i].item->type() == Item::FIELD_ITEM)
|
||||
list->push_back(trans[i].item);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -4840,11 +4840,11 @@ when_list2:
|
||||
table_ref:
|
||||
table_factor { $$=$1; }
|
||||
| join_table { $$=$1; }
|
||||
{
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->nest_last_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
join_table_list:
|
||||
@ -4934,20 +4934,20 @@ table_factor:
|
||||
sel->get_use_index(),
|
||||
sel->get_ignore_index())))
|
||||
YYABORT;
|
||||
sel->add_joined_table($$);
|
||||
sel->add_joined_table($$);
|
||||
}
|
||||
| '('
|
||||
{
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (lex->current_select->init_nested_join(lex->thd))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
join_table_list ')'
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->end_nested_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
|
||||
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
|
||||
| '(' SELECT_SYM select_derived ')' opt_table_alias
|
||||
|
147
sql/table.cc
147
sql/table.cc
@ -1481,10 +1481,65 @@ void st_table_list::calc_md5(char *buffer)
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
{
|
||||
if (ancestor->ancestor)
|
||||
ancestor->set_ancestor();
|
||||
table= ancestor->table;
|
||||
ancestor->table->grant= grant;
|
||||
/* process all tables of view */
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor)
|
||||
ancestor->set_ancestor();
|
||||
tbl->table->grant= grant;
|
||||
}
|
||||
/* if view contain only one table, substitute TABLE of it */
|
||||
if (!ancestor->next_local)
|
||||
table= ancestor->table;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Save old want_privilege and clear want_privilege
|
||||
|
||||
SYNOPSIS
|
||||
save_and_clear_want_privilege()
|
||||
*/
|
||||
|
||||
void st_table_list::save_and_clear_want_privilege()
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
{
|
||||
privilege_backup= tbl->table->grant.want_privilege;
|
||||
tbl->table->grant.want_privilege= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(tbl->view && tbl->ancestor &&
|
||||
tbl->ancestor->next_local);
|
||||
tbl->save_and_clear_want_privilege();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
restore want_privilege saved by save_and_clear_want_privilege
|
||||
|
||||
SYNOPSIS
|
||||
restore_want_privilege()
|
||||
*/
|
||||
|
||||
void st_table_list::restore_want_privilege()
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
tbl->table->grant.want_privilege= privilege_backup;
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(tbl->view && tbl->ancestor &&
|
||||
tbl->ancestor->next_local);
|
||||
tbl->restore_want_privilege();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1509,10 +1564,11 @@ void st_table_list::set_ancestor()
|
||||
|
||||
bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
{
|
||||
Item **transl;
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= &view->select_lex;
|
||||
SELECT_LEX *current_select_save= thd->lex->current_select;
|
||||
Item *item;
|
||||
TABLE_LIST *tbl;
|
||||
List_iterator_fast<Item> it(select->item_list);
|
||||
uint i= 0;
|
||||
bool save_set_query_id= thd->set_query_id;
|
||||
@ -1520,35 +1576,53 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
bool save_allow_sum_func= thd->allow_sum_func;
|
||||
DBUG_ENTER("st_table_list::setup_ancestor");
|
||||
|
||||
if (ancestor->ancestor &&
|
||||
ancestor->setup_ancestor(thd, conds))
|
||||
DBUG_RETURN(1);
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor && tbl->setup_ancestor(thd, conds))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (field_translation)
|
||||
{
|
||||
/* prevent look up in SELECTs tree */
|
||||
thd->lex->current_select= &thd->lex->select_lex;
|
||||
thd->lex->select_lex.no_wrap_view_item= 1;
|
||||
thd->set_query_id= 1;
|
||||
/* this view was prepared already on previous PS/SP execution */
|
||||
Item **end= field_translation + select->item_list.elements;
|
||||
for (Item **item= field_translation; item < end; item++)
|
||||
Field_translator *end= field_translation + select->item_list.elements;
|
||||
/* real rights will be checked in VIEW field */
|
||||
save_and_clear_want_privilege();
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
for (transl= field_translation; transl < end; transl++)
|
||||
{
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
|
||||
if (!transl->item->fixed &&
|
||||
transl->item->fix_fields(thd, ancestor, &transl->item))
|
||||
goto err;
|
||||
ancestor->table->grant.want_privilege= want_privilege;
|
||||
}
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->on_expr && !tbl->on_expr->fixed &&
|
||||
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
|
||||
goto err;
|
||||
}
|
||||
if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
|
||||
goto err;
|
||||
restore_want_privilege();
|
||||
|
||||
/* WHERE/ON resolved => we can rename fields */
|
||||
for (transl= field_translation; transl < end; transl++)
|
||||
{
|
||||
transl->item->rename((char *)transl->name);
|
||||
}
|
||||
goto ok;
|
||||
}
|
||||
|
||||
/* view fields translation table */
|
||||
if (!(transl=
|
||||
(Item**)(thd->current_arena->alloc(select->item_list.elements * sizeof(Item*)))))
|
||||
(Field_translator*)(thd->current_arena->
|
||||
alloc(select->item_list.elements *
|
||||
sizeof(Field_translator)))))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
@ -1564,22 +1638,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
used fields correctly.
|
||||
*/
|
||||
thd->set_query_id= 1;
|
||||
/* real rights will be checked in VIEW field */
|
||||
save_and_clear_want_privilege();
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
while ((item= it++))
|
||||
{
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
/* save original name of view column */
|
||||
char *name= item->name;
|
||||
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
|
||||
goto err;
|
||||
ancestor->table->grant.want_privilege= want_privilege;
|
||||
transl[i++]= item;
|
||||
/* set new item get in fix fields and original column name */
|
||||
transl[i].name= name;
|
||||
transl[i++].item= item;
|
||||
}
|
||||
field_translation= transl;
|
||||
/* TODO: sort this list? Use hash for big number of fields */
|
||||
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->on_expr && !tbl->on_expr->fixed &&
|
||||
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
|
||||
goto err;
|
||||
}
|
||||
if (where)
|
||||
{
|
||||
Item_arena *arena= thd->current_arena, backup;
|
||||
@ -1620,6 +1701,16 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
}
|
||||
restore_want_privilege();
|
||||
|
||||
/* WHERE/ON resolved => we can rename fields */
|
||||
{
|
||||
Field_translator *end= field_translation + select->item_list.elements;
|
||||
for (transl= field_translation; transl < end; transl++)
|
||||
{
|
||||
transl->item->rename((char *)transl->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* full text function moving to current select */
|
||||
if (view->select_lex.ftfunc_list->elements)
|
||||
@ -1674,7 +1765,7 @@ Item *Field_iterator_table::item(THD *thd)
|
||||
|
||||
const char *Field_iterator_view::name()
|
||||
{
|
||||
return (*ptr)->name;
|
||||
return ptr->name;
|
||||
}
|
||||
|
||||
|
||||
|
18
sql/table.h
18
sql/table.h
@ -190,6 +190,13 @@ struct st_table {
|
||||
|
||||
struct st_lex;
|
||||
|
||||
|
||||
struct Field_translator
|
||||
{
|
||||
Item *item;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
typedef struct st_table_list
|
||||
{
|
||||
/* link in a local table list (used by SQL_LIST) */
|
||||
@ -215,13 +222,15 @@ typedef struct st_table_list
|
||||
/* link to select_lex where this table was used */
|
||||
st_select_lex *select_lex;
|
||||
st_lex *view; /* link on VIEW lex for merging */
|
||||
Item **field_translation; /* array of VIEW fields */
|
||||
Field_translator *field_translation; /* array of VIEW fields */
|
||||
/* ancestor of this table (VIEW merge algorithm) */
|
||||
st_table_list *ancestor;
|
||||
/* most upper view this table belongs to */
|
||||
st_table_list *belong_to_view;
|
||||
/* next_global before adding VIEW tables */
|
||||
st_table_list *old_next;
|
||||
/* list of join table tree leaves */
|
||||
st_table_list *next_leaf;
|
||||
Item *where; /* VIEW WHERE clause condition */
|
||||
LEX_STRING query; /* text of (CRETE/SELECT) statement */
|
||||
LEX_STRING md5; /* md5 of query tesxt */
|
||||
@ -234,6 +243,7 @@ typedef struct st_table_list
|
||||
ulonglong revision; /* revision control number */
|
||||
ulonglong algorithm; /* 0 any, 1 tmp tables , 2 merging */
|
||||
uint effective_algorithm; /* which algorithm was really used */
|
||||
uint privilege_backup; /* place for saving privileges */
|
||||
GRANT_INFO grant;
|
||||
thr_lock_type lock_type;
|
||||
uint outer_join; /* Which join type */
|
||||
@ -265,6 +275,8 @@ typedef struct st_table_list
|
||||
bool setup_ancestor(THD *thd, Item **conds);
|
||||
bool placeholder() {return derived || view; }
|
||||
void print(THD *thd, String *str);
|
||||
void save_and_clear_want_privilege();
|
||||
void restore_want_privilege();
|
||||
inline st_table_list *next_independent()
|
||||
{
|
||||
if (view)
|
||||
@ -305,14 +317,14 @@ public:
|
||||
|
||||
class Field_iterator_view: public Field_iterator
|
||||
{
|
||||
Item **ptr, **array_end;
|
||||
Field_translator *ptr, *array_end;
|
||||
public:
|
||||
Field_iterator_view() :ptr(0), array_end(0) {}
|
||||
void set(TABLE_LIST *table);
|
||||
void next() { ptr++; }
|
||||
bool end_of_fields() { return ptr == array_end; }
|
||||
const char *name();
|
||||
Item *item(THD *thd) { return *ptr; }
|
||||
Item *item(THD *thd) { return ptr->item; }
|
||||
Field *field() { return 0; }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user