diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 124 |
1 files changed, 95 insertions, 29 deletions
diff --git a/sql/item.cc b/sql/item.cc index 8dfb8fb5587..0ca557a8fc4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -23,6 +23,7 @@ #include <m_ctype.h> #include "my_dir.h" #include "sp_rcontext.h" +#include "sql_acl.h" static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, @@ -350,7 +351,8 @@ bool DTCollation::aggregate(DTCollation &dt) } Item_field::Item_field(Field *f) - :Item_ident(NullS, f->table_name, f->field_name) + :Item_ident(NullS, f->table_name, f->field_name), + have_privileges(0), any_privileges(0) { set_field(f); collation.set(DERIVATION_IMPLICIT); @@ -359,7 +361,8 @@ Item_field::Item_field(Field *f) Item_field::Item_field(THD *thd, Field *f) :Item_ident(NullS, thd->strdup(f->table_name), - thd->strdup(f->field_name)) + thd->strdup(f->field_name)), + have_privileges(0), any_privileges(0) { set_field(f); collation.set(DERIVATION_IMPLICIT); @@ -370,7 +373,9 @@ Item_field::Item_field(THD *thd, Field *f) Item_field::Item_field(THD *thd, Item_field *item) :Item_ident(thd, item), field(item->field), - result_field(item->result_field) + result_field(item->result_field), + have_privileges(item->have_privileges), + any_privileges(item->any_privileges) { collation.set(DERIVATION_IMPLICIT); } @@ -1223,10 +1228,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); if (!field) // If field is not checked { - TABLE_LIST *where= 0; bool upward_lookup= 0; Field *tmp= (Field *)not_found_field; - if ((tmp= find_field_in_tables(thd, this, tables, &where, 0)) == + if ((tmp= find_field_in_tables(thd, this, tables, ref, 0, + !any_privileges)) == not_found_field) { /* @@ -1259,18 +1264,19 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) { // it is primary INSERT st_select_lex => skip first table resolving - table_list= table_list->next; + table_list= table_list->next_local; } Item_subselect *prev_subselect_item= prev_unit->item; if ((tmp= find_field_in_tables(thd, this, - table_list, &where, - 0)) != not_found_field) + table_list, ref, + 0, 1)) != not_found_field) { - if (!tmp) - return -1; - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; + if (tmp && tmp != view_ref_found) + { + prev_subselect_item->used_tables_cache|= tmp->table->map; + prev_subselect_item->const_item_cache= 0; + } break; } if (sl->resolve_mode == SELECT_LEX::SELECT_MODE && @@ -1310,7 +1316,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) else { // Call to report error - find_field_in_tables(thd, this, tables, &where, 1); + find_field_in_tables(thd, this, tables, ref, 1, 1); } return -1; } @@ -1348,8 +1354,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item_ref *rf; *ref= rf= new Item_ref(ref, *ref, - (where->db[0]?where->db:0), - (char *)where->alias, + (cached_table->db[0]?cached_table->db:0), + (char *)cached_table->alias, (char *)field_name); if (!rf) return 1; @@ -1364,7 +1370,20 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) else if (!tmp) return -1; - set_field(tmp); + /* + if it is not expression from merged VIEW we will set this field. + + We can leave expression substituted from view for next PS/SP rexecution + (i.e. do not register this substitution for reverting on cleupup() + (register_item_tree_changing())), because this subtree will be + fix_field'ed during setup_tables()->setup_ancestor() (i.e. before + all other expressions of query, and references on tables which do + not present in query will not make problems. + + Also we suppose that view can't be changed during PS/SP life. + */ + if (tmp != view_ref_found) + set_field(tmp); } else if (thd->set_query_id && field->query_id != thd->query_id) { @@ -1374,6 +1393,36 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) table->used_fields++; table->used_keys.intersect(field->part_of_key); } +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (any_privileges) + { + char *db, *tab; + if (cached_table->view) + { + db= cached_table->view_db.str; + tab= cached_table->view_name.str; + } + else + { + db= cached_table->db; + tab= cached_table->real_name; + } + if (!(have_privileges= (get_column_grant(thd, &field->table->grant, + db, tab, field_name) & + VIEW_ANY_ACL))) + { + my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, + ER(ER_COLUMNACCESS_DENIED_ERROR), + MYF(0), + "ANY", + thd->priv_user, + thd->host_or_ip, + field_name, + tab); + return 1; + } + } +#endif fixed= 1; return 0; } @@ -1870,13 +1919,13 @@ bool Item_field::send(Protocol *protocol, String *buffer) Find field in select list having the same name */ -bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) +bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) { DBUG_ASSERT(fixed == 0); uint counter; if (!ref) { - TABLE_LIST *where= 0, *table_list; + TABLE_LIST *table_list; bool upward_lookup= 0; SELECT_LEX_UNIT *prev_unit= thd->lex->current_select->master_unit(); SELECT_LEX *sl= prev_unit->outer_select(); @@ -1929,14 +1978,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) { // it is primary INSERT st_select_lex => skip first table resolving - table_list= table_list->next; + table_list= table_list->next_local; } if ((tmp= find_field_in_tables(thd, this, - table_list, &where, - 0)) != not_found_field) + table_list, reference, + 0, 1)) != not_found_field) { - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; + if (tmp && tmp != view_ref_found) + { + prev_subselect_item->used_tables_cache|= tmp->table->map; + prev_subselect_item->const_item_cache= 0; + } break; } @@ -1975,12 +2027,26 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) else if (tmp != not_found_field) { ref= 0; // To prevent "delete *ref;" on ~Item_erf() of this item - Item_field* fld; - if (!((*reference)= fld= new Item_field(tmp))) - return 1; - register_item_tree_changing(reference); - mark_as_dependent(thd, last, thd->lex->current_select, fld); - return 0; + if (tmp != view_ref_found) + { + Item_field* fld; + if (!((*reference)= fld= new Item_field(tmp))) + return 1; + mark_as_dependent(thd, last, thd->lex->current_select, fld); + return 0; + register_item_tree_changing(reference); + } + /* + We can leave expression substituted from view for next PS/SP + rexecution (i.e. do not register this substitution for reverting + on cleupup() (register_item_tree_changing())), because this + subtree will be fix_field'ed during + setup_tables()->setup_ancestor() (i.e. before all other + expressions of query, and references on tables which do not + present in query will not make problems. + + Also we suppose that view can't be changed during PS/SP life. + */ } else { |