summaryrefslogtreecommitdiff
path: root/sql/item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.cc')
-rw-r--r--sql/item.cc292
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);