diff options
Diffstat (limited to 'sql/item.cc')
-rw-r--r-- | sql/item.cc | 292 |
1 files changed, 242 insertions, 50 deletions
diff --git a/sql/item.cc b/sql/item.cc index e9ef3b6a763..ecbe2d22fa4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -22,6 +22,8 @@ #include "mysql_priv.h" #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, @@ -41,7 +43,7 @@ void item_init(void) } Item::Item(): - fixed(0) + name_length(0), fixed(0) { marker= 0; maybe_null=null_value=with_sum_func=unsigned_flag=0; @@ -96,9 +98,9 @@ void Item::print_item_w_name(String *str) print(str); if (name) { - str->append(" AS `", 5); - str->append(name); - str->append('`'); + THD *thd= current_thd; + str->append(" AS ", 4); + append_identifier(thd, str, name, strlen(name)); } } @@ -174,12 +176,15 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) { /* Empty string, used by AS or internal function like last_insert_id() */ name= (char*) str; + name_length= 0; return; } if (cs->ctype) { - // This will probably need a better implementation in the future: - // a function in CHARSET_INFO structure. + /* + This will probably need a better implementation in the future: + a function in CHARSET_INFO structure. + */ while (length && !my_isgraph(cs,*str)) { // Fix problem with yacc length--; @@ -189,12 +194,12 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) if (!my_charset_same(cs, system_charset_info)) { uint32 res_length; - name= sql_strmake_with_convert(str, length, cs, + name= sql_strmake_with_convert(str, name_length= length, cs, MAX_ALIAS_NAME, system_charset_info, &res_length); } else - name=sql_strmake(str, min(length,MAX_ALIAS_NAME)); + name= sql_strmake(str, (name_length= min(length,MAX_ALIAS_NAME))); } @@ -265,6 +270,34 @@ CHARSET_INFO *Item::default_charset() return current_thd->variables.collation_connection; } + +Item * +Item_splocal::this_item() +{ + THD *thd= current_thd; + + return thd->spcont->get_item(m_offset); +} + +Item * +Item_splocal::this_const_item() const +{ + THD *thd= current_thd; + + return thd->spcont->get_item(m_offset); +} + +Item::Type +Item_splocal::type() const +{ + THD *thd= current_thd; + + if (thd->spcont) + return thd->spcont->get_item(m_offset)->type(); + return NULL_ITEM; // Anything but SUBSELECT_ITEM +} + + bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion) { nagg++; @@ -351,7 +384,8 @@ bool DTCollation::aggregate(DTCollation &dt, bool superset_conversion) } 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); @@ -360,7 +394,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); @@ -371,7 +406,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); } @@ -414,6 +451,36 @@ const char *Item_ident::full_name() const return tmp; } +void Item_ident::print(String *str) +{ + THD *thd= current_thd; + if (!table_name || !field_name) + { + const char *nm= field_name ? field_name : name ? name : "tmp_field"; + append_identifier(thd, str, nm, strlen(nm)); + return; + } + if (db_name && db_name[0]) + { + append_identifier(thd, str, db_name, strlen(db_name)); + str->append('.'); + append_identifier(thd, str, table_name, strlen(table_name)); + str->append('.'); + append_identifier(thd, str, field_name, strlen(field_name)); + } + else + { + if (table_name[0]) + { + append_identifier(thd, str, table_name, strlen(table_name)); + str->append('.'); + append_identifier(thd, str, field_name, strlen(field_name)); + } + else + append_identifier(thd, str, field_name, strlen(field_name)); + } +} + /* ARGSUSED */ String *Item_field::val_str(String *str) { @@ -1109,8 +1176,27 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -/* End of Item_param related */ +void Item_param::print(String *str) +{ + if (state == NO_VALUE) + { + str->append('?'); + } + else + { + char buffer[80]; + String tmp(buffer, sizeof(buffer), &my_charset_bin); + const String *res; + res= query_val_str(&tmp); + str->append(*res); + } +} + + +/**************************************************************************** + Item_copy_string +****************************************************************************/ void Item_copy_string::copy() { @@ -1224,10 +1310,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) { /* @@ -1263,12 +1349,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) 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; - enum_parsing_place place= - prev_subselect_item->parsing_place; + enum_parsing_place place= prev_subselect_item->parsing_place; /* check table fields only if subquery used somewhere out of HAVING or SELECT list or outer SELECT do not use groupping (i.e. tables @@ -1278,15 +1363,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) place != SELECT_LIST) || (sl->with_sum_func == 0 && sl->group_list.elements == 0)) && (tmp= find_field_in_tables(thd, this, - table_list, &where, - 0)) != not_found_field) - { - if (!tmp) - return -1; - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; - break; - } + table_list, ref, + 0, 1)) != not_found_field) + { + 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 && (refer= find_item_in_list(this, sl->item_list, &counter, REPORT_EXCEPT_NOT_FOUND)) != @@ -1324,7 +1410,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; } @@ -1362,8 +1448,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; @@ -1378,7 +1464,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) { @@ -1388,6 +1487,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; } @@ -1884,13 +2013,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(); @@ -1943,12 +2072,11 @@ 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; } - enum_parsing_place place= - prev_subselect_item->parsing_place; + enum_parsing_place place= prev_subselect_item->parsing_place; /* - check table fields only if subquery used somewhere out of HAVING + Check table fields only if subquery used somewhere out of HAVING or SELECT list or outer SELECT do not use groupping (i.e. tables are accessable) */ @@ -1956,14 +2084,18 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) place != SELECT_LIST) || (sl->with_sum_func == 0 && sl->group_list.elements == 0)) && (tmp= find_field_in_tables(thd, this, - table_list, &where, - 0)) != not_found_field) - { - prev_subselect_item->used_tables_cache|= tmp->table->map; - prev_subselect_item->const_item_cache= 0; - break; - } - // Reference is not found => depend from outer (or just error) + table_list, reference, + 0, 1)) != not_found_field) + { + if (tmp && tmp != view_ref_found) + { + prev_subselect_item->used_tables_cache|= tmp->table->map; + prev_subselect_item->const_item_cache= 0; + } + break; + } + + // Reference is not found => depend from outer (or just error) prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->const_item_cache= 0; @@ -1998,12 +2130,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 { @@ -2068,6 +2214,7 @@ void Item_ref::cleanup() { DBUG_ENTER("Item_ref::cleanup"); Item_ident::cleanup(); + result_field= 0; if (hook_ptr) *hook_ptr= orig_item; DBUG_VOID_RETURN; @@ -2083,6 +2230,51 @@ void Item_ref::print(String *str) } +bool Item_ref::send(Protocol *prot, String *tmp) +{ + if (result_field) + return prot->store(result_field); + return (*ref)->send(prot, tmp); +} + + +double Item_ref::val_result() +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0.0; + return result_field->val_real(); + } + return val(); +} + + +longlong Item_ref::val_int_result() +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + return result_field->val_int(); + } + return val_int(); +} + + +String *Item_ref::str_result(String* str) +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + str->set_charset(str_value.charset()); + return result_field->val_str(str, &str_value); + } + return val_str(str); +} + + void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); |