summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2004-09-14 19:28:29 +0300
committerunknown <bell@sanja.is.com.ua>2004-09-14 19:28:29 +0300
commit55a8c28c27778d018a145ce25e61bdcda7a764a5 (patch)
tree44ca229eb83d0543674b391c46f4d3a77539bfb7 /sql
parentae70baf21ce2b8e17bacf1ca57aed08c9cf745ed (diff)
downloadmariadb-git-55a8c28c27778d018a145ce25e61bdcda7a764a5.tar.gz
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)
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc34
-rw-r--r--sql/item.h27
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/item_subselect.cc7
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/sp.cc3
-rw-r--r--sql/sql_base.cc212
-rw-r--r--sql/sql_delete.cc7
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_insert.cc20
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_load.cc3
-rw-r--r--sql/sql_olap.cc2
-rw-r--r--sql/sql_parse.cc2
-rw-r--r--sql/sql_prepare.cc7
-rw-r--r--sql/sql_select.cc44
-rw-r--r--sql/sql_update.cc35
-rw-r--r--sql/sql_view.cc91
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.cc147
-rw-r--r--sql/table.h18
23 files changed, 521 insertions, 179 deletions
diff --git a/sql/item.cc b/sql/item.cc
index cbb760156b3..1e8b4d8630d 100644
--- a/sql/item.cc
+++ b/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;
diff --git a/sql/item.h b/sql/item.h
index a237e7ce6f5..8dc928574e1 100644
--- a/sql/item.h
+++ b/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); }
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index e7bef18e629..b07dd10a5bc 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -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);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 25bb2701101..5b730ab983a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -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);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 029da71c41b..a43ec6f00ed 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 314decb7041..56d20b58072 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -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))
diff --git a/sql/sp.cc b/sql/sp.cc
index 6475b64eb18..5b0afbf5558 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -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++)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 80090ba288e..c0deeba6148 100644
--- a/sql/sql_base.cc
+++ b/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)
@@ -2612,13 +2634,45 @@ 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 */
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index f9dba49d2e3..4885470846b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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 */
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 8fc0671c808..93900dbec8a 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -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)))
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ac63445c1de..03028a13d19 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f5382e6df99..e6c9f973b9b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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);
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index d43b1f81f3d..a32b8465a88 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 9b050c0863a..e0138e642e0 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -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)
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 20fd7fe2ee0..c287b9e71e7 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -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,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e1baf47b234..115dda49666 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 124db39ef3f..99510d900bc 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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();
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 789a4dc3086..ab7af598673 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index dc867968262..79f3950e21f 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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> &not_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> &not_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
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 2364be228f8..12923af0ecf 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -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;
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fab8f19950f..ed2243c4b77 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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
diff --git a/sql/table.cc b/sql/table.cc
index e6b84a5acb0..851e99ef4f6 100644
--- a/sql/table.cc
+++ b/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;
}
diff --git a/sql/table.h b/sql/table.h
index f31c3c21d63..b5139919889 100644
--- a/sql/table.h
+++ b/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; }
};