summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc26
-rw-r--r--sql/item.h10
-rw-r--r--sql/mysql_priv.h22
-rw-r--r--sql/sql_base.cc121
-rw-r--r--sql/sql_select.cc8
5 files changed, 118 insertions, 69 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 257687ebaaf..c5d8a62761c 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3320,7 +3320,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
ORDER *group_list= (ORDER*) select->group_list.first;
bool ambiguous_fields= FALSE;
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
/*
Search for a column or derived column named as 'ref' in the SELECT
@@ -3328,8 +3328,10 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
*/
if (!(select_ref= find_item_in_list(ref, *(select->get_item_list()),
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used)))
+ &resolution)))
return NULL; /* Some error occurred. */
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ ref->alias_name_used= TRUE;
/* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
if (select->having_fix_field && !ref->with_sum_func && group_list)
@@ -3630,9 +3632,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
*ref= NULL; // Don't call set_properties()
rf= (place == IN_HAVING ?
new Item_ref(context, ref, (char*) table_name,
- (char*) field_name) :
+ (char*) field_name, alias_name_used) :
new Item_direct_ref(context, ref, (char*) table_name,
- (char*) field_name));
+ (char*) field_name, alias_name_used));
*ref= save;
if (!rf)
return -1;
@@ -3750,12 +3752,14 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
if (thd->lex->current_select->is_item_list_lookup)
{
uint counter;
- bool not_used;
+ enum_resolution_type resolution;
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
- &not_used);
+ &resolution);
if (!res)
return 1;
+ if (resolution == RESOLVED_AGAINST_ALIAS)
+ alias_name_used= TRUE;
if (res != (Item **)not_found_item)
{
if ((*res)->type() == Item::FIELD_ITEM)
@@ -4898,10 +4902,12 @@ Item *Item_field::update_value_transformer(byte *select_arg)
Item_ref::Item_ref(Name_resolution_context *context_arg,
Item **item, const char *table_name_arg,
- const char *field_name_arg)
+ const char *field_name_arg,
+ bool alias_name_used_arg)
:Item_ident(context_arg, NullS, table_name_arg, field_name_arg),
result_field(0), ref(item)
{
+ alias_name_used= alias_name_used_arg;
/*
This constructor used to create some internals references over fixed items
*/
@@ -5184,11 +5190,13 @@ void Item_ref::set_properties()
*/
with_sum_func= (*ref)->with_sum_func;
unsigned_flag= (*ref)->unsigned_flag;
+ fixed= 1;
+ if (alias_name_used)
+ return;
if ((*ref)->type() == FIELD_ITEM)
alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
else
alias_name_used= TRUE; // it is not field, so it is was resolved by alias
- fixed= 1;
}
@@ -5206,7 +5214,7 @@ void Item_ref::print(String *str)
if (ref)
{
if ((*ref)->type() != Item::CACHE_ITEM && ref_type() != VIEW_REF &&
- ref_type() != OUTER_REF && name && alias_name_used)
+ !table_name && name && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, name, (uint) strlen(name));
diff --git a/sql/item.h b/sql/item.h
index d792f95055d..2a121523423 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1851,7 +1851,8 @@ public:
with Bar, and if we have a more broader set of problems like this.
*/
Item_ref(Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const char *field_name_arg);
+ const char *table_name_arg, const char *field_name_arg,
+ bool alias_name_used_arg= FALSE);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
@@ -1926,8 +1927,11 @@ class Item_direct_ref :public Item_ref
public:
Item_direct_ref(Name_resolution_context *context_arg, Item **item,
const char *table_name_arg,
- const char *field_name_arg)
- :Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
+ const char *field_name_arg,
+ bool alias_name_used_arg= FALSE)
+ :Item_ref(context_arg, item, table_name_arg,
+ field_name_arg, alias_name_used_arg)
+ {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 7c9b43f23b9..cf5e9799fae 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1008,9 +1008,29 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds,
bool allow_null_cond, int *error);
extern Item **not_found_item;
+
+/*
+ This enumeration type is used only by the function find_item_in_list
+ to return the info on how an item has been resolved against a list
+ of possibly aliased items.
+ The item can be resolved:
+ - against an alias name of the list's element (RESOLVED_AGAINST_ALIAS)
+ - against non-aliased field name of the list (RESOLVED_WITH_NO_ALIAS)
+ - against an aliased field name of the list (RESOLVED_BEHIND_ALIAS)
+ - ignoring the alias name in cases when SQL requires to ignore aliases
+ (e.g. when the resolved field reference contains a table name or
+ when the resolved item is an expression) (RESOLVED_IGNORING_ALIAS)
+*/
+enum enum_resolution_type {
+ NOT_RESOLVED=0,
+ RESOLVED_IGNORING_ALIAS,
+ RESOLVED_BEHIND_ALIAS,
+ RESOLVED_WITH_NO_ALIAS,
+ RESOLVED_AGAINST_ALIAS
+};
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error,
- bool *unaliased);
+ enum_resolution_type *resolution);
bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd, Name_resolution_context *context,
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 9945057cd1b..0ebfd2b1044 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3468,10 +3468,13 @@ find_field_in_tables(THD *thd, Item_ident *item,
return not_found_item, report other errors,
return 0
IGNORE_ERRORS Do not report errors, return 0 if error
- unaliased Set to true if item is field which was found
- by original field name and not by its alias
- in item list. Set to false otherwise.
-
+ resolution Set to the resolution type if the item is found
+ (it says whether the item is resolved
+ against an alias name,
+ or as a field name without alias,
+ or as a field hidden by alias,
+ or ignoring alias)
+
RETURN VALUES
0 Item is not found or item is not unique,
error message is reported
@@ -3487,7 +3490,8 @@ Item **not_found_item= (Item**) 0x1;
Item **
find_item_in_list(Item *find, List<Item> &items, uint *counter,
- find_item_error_report_type report_error, bool *unaliased)
+ find_item_error_report_type report_error,
+ enum_resolution_type *resolution)
{
List_iterator<Item> li(items);
Item **found=0, **found_unaliased= 0, *item;
@@ -3501,10 +3505,9 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
*/
bool is_ref_by_name= 0;
uint unaliased_counter;
-
LINT_INIT(unaliased_counter); // Dependent on found_unaliased
- *unaliased= FALSE;
+ *resolution= NOT_RESOLVED;
is_ref_by_name= (find->type() == Item::FIELD_ITEM ||
find->type() == Item::REF_ITEM);
@@ -3571,63 +3574,77 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
}
found_unaliased= li.ref();
unaliased_counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
if (db_name)
break; // Perfect match
}
}
- else if (!my_strcasecmp(system_charset_info, item_field->name,
- field_name))
- {
- /*
- If table name was not given we should scan through aliases
- (or non-aliased fields) first. We are also checking unaliased
- name of the field in then next else-if, to be able to find
- instantly field (hidden by alias) if no suitable alias (or
- non-aliased field) was found.
- */
- if (found)
- {
- if ((*found)->eq(item, 0))
- continue; // Same field twice
- if (report_error != IGNORE_ERRORS)
- my_error(ER_NON_UNIQ_ERROR, MYF(0),
- find->full_name(), current_thd->where);
- return (Item**) 0;
- }
- found= li.ref();
- *counter= i;
- }
- else if (!my_strcasecmp(system_charset_info, item_field->field_name,
- field_name))
+ else
{
- /*
- We will use un-aliased field or react on such ambiguities only if
- we won't be able to find aliased field.
- Again if we have ambiguity with field outside of select list
- we should prefer fields from select list.
- */
- if (found_unaliased)
+ int fname_cmp= my_strcasecmp(system_charset_info,
+ item_field->field_name,
+ field_name);
+ if (!my_strcasecmp(system_charset_info,
+ item_field->name,field_name))
{
- if ((*found_unaliased)->eq(item, 0))
- continue; // Same field twice
- found_unaliased_non_uniq= 1;
+ /*
+ If table name was not given we should scan through aliases
+ and non-aliased fields first. We are also checking unaliased
+ name of the field in then next else-if, to be able to find
+ instantly field (hidden by alias) if no suitable alias or
+ non-aliased field was found.
+ */
+ if (found)
+ {
+ if ((*found)->eq(item, 0))
+ continue; // Same field twice
+ if (report_error != IGNORE_ERRORS)
+ my_error(ER_NON_UNIQ_ERROR, MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item**) 0;
+ }
+ found= li.ref();
+ *counter= i;
+ *resolution= fname_cmp ? RESOLVED_AGAINST_ALIAS:
+ RESOLVED_WITH_NO_ALIAS;
}
- else
+ else if (!fname_cmp)
{
+ /*
+ We will use non-aliased field or react on such ambiguities only if
+ we won't be able to find aliased field.
+ Again if we have ambiguity with field outside of select list
+ we should prefer fields from select list.
+ */
+ if (found_unaliased)
+ {
+ if ((*found_unaliased)->eq(item, 0))
+ continue; // Same field twice
+ found_unaliased_non_uniq= 1;
+ }
found_unaliased= li.ref();
unaliased_counter= i;
}
}
}
- else if (!table_name && (find->eq(item,0) ||
- is_ref_by_name && find->name && item->name &&
- !my_strcasecmp(system_charset_info,
- item->name,find->name)))
- {
- found= li.ref();
- *counter= i;
- break;
- }
+ else if (!table_name)
+ {
+ if (is_ref_by_name && find->name && item->name &&
+ !my_strcasecmp(system_charset_info,item->name,find->name))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_AGAINST_ALIAS;
+ break;
+ }
+ else if (find->eq(item,0))
+ {
+ found= li.ref();
+ *counter= i;
+ *resolution= RESOLVED_IGNORING_ALIAS;
+ break;
+ }
+ }
}
if (!found)
{
@@ -3642,7 +3659,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
found= found_unaliased;
*counter= unaliased_counter;
- *unaliased= TRUE;
+ *resolution= RESOLVED_BEHIND_ALIAS;
}
}
if (found)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5202f35f4de..7538d3bf599 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13158,7 +13158,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **select_item; /* The corresponding item from the SELECT clause. */
Field *from_field; /* The corresponding field from the FROM clause. */
uint counter;
- bool unaliased;
+ enum_resolution_type resolution;
/*
Local SP variables may be int but are expressions, not positions.
@@ -13181,7 +13181,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
}
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
select_item= find_item_in_list(order_item, fields, &counter,
- REPORT_EXCEPT_NOT_FOUND, &unaliased);
+ REPORT_EXCEPT_NOT_FOUND, &resolution);
if (!select_item)
return TRUE; /* The item is not unique, or some other error occured. */
@@ -13195,7 +13195,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
original field name, we should additionaly check if we have conflict
for this name (in case if we would perform lookup in all tables).
*/
- if (unaliased && !order_item->fixed &&
+ if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed &&
order_item->fix_fields(thd, order->item))
return TRUE;
@@ -13429,7 +13429,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
thd->set_query_id=1; // Not really needed, but...
uint counter;
- bool not_used;
+ enum_resolution_type not_used;
for (; new_field ; new_field= new_field->next)
{
if ((item= find_item_in_list(*new_field->item, fields, &counter,