mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
WL#1972 "Evaluate HAVING before SELECT select-list"
- Changed name resolution for GROUP BY so that derived columns do not shadow table columns from the FROM clause. As a result GROUP BY now is handled as a true ANSI extentsion. - Issue a warning when HAVING is resolved into ambiguous columns, and prefer the columns from the GROUP BY clause over SELECT columns. mysql-test/r/having.result: Correct result for updated GROUP BY name resolution. sql/item.cc: - prefer GROUP columns, but if none is found use SELECT list - issue a waring when a field may be resolved ambiguously - more/fixed comments sql/mysql_priv.h: More flexible find_field_in_tables(). sql/sp.cc: More flexible find_field_in_tables(). sql/sql_base.cc: More flexible find_field_in_tables(). sql/sql_help.cc: More flexible find_field_in_tables(). sql/sql_select.cc: - name resolution of GROUP/ORDER BY column references is differentiated: - GROUP BY is resolved in SELECT and FROM clauses - ORDER BY is resolved only in SELECT (as before) - more informative variable names - more comments
This commit is contained in:
@ -221,6 +221,9 @@ select count(*) from wl1972 group by s1 having s1 is null;
|
|||||||
count(*)
|
count(*)
|
||||||
select s1*0 as s1 from wl1972 group by s1 having s1 <> 0;
|
select s1*0 as s1 from wl1972 group by s1 having s1 <> 0;
|
||||||
s1
|
s1
|
||||||
|
0
|
||||||
|
0
|
||||||
|
0
|
||||||
select s1*0 from wl1972 group by s1 having s1 = 0;
|
select s1*0 from wl1972 group by s1 having s1 = 0;
|
||||||
s1*0
|
s1*0
|
||||||
select s1 from wl1972 group by 1 having 1 = 0;
|
select s1 from wl1972 group by 1 having 1 = 0;
|
||||||
|
69
sql/item.cc
69
sql/item.cc
@ -1397,7 +1397,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
{
|
{
|
||||||
bool upward_lookup= 0;
|
bool upward_lookup= 0;
|
||||||
Field *tmp= (Field *)not_found_field;
|
Field *tmp= (Field *)not_found_field;
|
||||||
if ((tmp= find_field_in_tables(thd, this, tables, ref, 0,
|
if ((tmp= find_field_in_tables(thd, this, tables, ref,
|
||||||
|
IGNORE_EXCEPT_NON_UNIQUE,
|
||||||
!any_privileges)) ==
|
!any_privileges)) ==
|
||||||
not_found_field)
|
not_found_field)
|
||||||
{
|
{
|
||||||
@ -1449,7 +1450,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
(sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
|
(sl->with_sum_func == 0 && sl->group_list.elements == 0)) &&
|
||||||
(tmp= find_field_in_tables(thd, this,
|
(tmp= find_field_in_tables(thd, this,
|
||||||
table_list, ref,
|
table_list, ref,
|
||||||
0, 1)) != not_found_field)
|
IGNORE_EXCEPT_NON_UNIQUE, 1)) !=
|
||||||
|
not_found_field)
|
||||||
{
|
{
|
||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
@ -1505,7 +1507,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Call to report error
|
// Call to report error
|
||||||
find_field_in_tables(thd, this, tables, ref, 1, 1);
|
find_field_in_tables(thd, this, tables, ref, REPORT_ALL_ERRORS, 1);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -2347,31 +2349,39 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Item_ref::fix_fields()
|
Item_ref::fix_fields()
|
||||||
thd [in] Current thread
|
thd [in] current thread
|
||||||
tables [in] The tables in the FROM clause
|
tables [in] the tables in the FROM clause
|
||||||
reference [in/out] View column if this item was resolved to a view column
|
reference [in/out] view column if this item was resolved to a view column
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
The method resolves the column reference represented by this as an Item
|
The method resolves the column reference represented by 'this' as a column
|
||||||
present in either of: GROUP BY clause, SELECT clause, outer queries. It is
|
present in one of: GROUP BY clause, SELECT clause, outer queries. It is
|
||||||
used for columns in the HAVING clause which are not under aggregate
|
used for columns in the HAVING clause which are not under aggregate
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
|
The general idea behind the name resolution algorithm is that it searches
|
||||||
|
both the SELECT and GROUP BY clauses, and in case of a name conflict
|
||||||
|
prefers GROUP BY column names over SELECT names. We extend ANSI SQL in that
|
||||||
|
when no GROUP BY column is found, then a HAVING name is resolved as a
|
||||||
|
possibly derived SELECT column.
|
||||||
|
|
||||||
The name resolution algorithm used is:
|
The name resolution algorithm used is:
|
||||||
|
|
||||||
resolve_extended([T_j].col_ref_i)
|
resolve_extended([T_j].col_ref_i)
|
||||||
{
|
{
|
||||||
Search for a column named col_ref_i [in table T_j]
|
|
||||||
in the GROUP BY clause of Q.
|
|
||||||
|
|
||||||
Search for a column or derived column named col_ref_i [in table T_j]
|
Search for a column or derived column named col_ref_i [in table T_j]
|
||||||
in the SELECT list of Q.
|
in the SELECT list of Q.
|
||||||
|
|
||||||
if found different columns with the same name in GROUP BY and SELECT
|
Search for a column named col_ref_i [in table T_j]
|
||||||
issue an error.
|
in the GROUP BY clause of Q.
|
||||||
|
|
||||||
// Lookup in outer queries.
|
If found different columns with the same name in GROUP BY and SELECT
|
||||||
if such a column is NOT found AND there are outer queries
|
issue a warning and return the GROUP BY column,
|
||||||
|
otherwise return the found SELECT column.
|
||||||
|
|
||||||
|
if such a column is NOT found AND // Lookup in outer queries.
|
||||||
|
there are outer queries
|
||||||
{
|
{
|
||||||
for each outer query Q_k beginning from the inner-most one
|
for each outer query Q_k beginning from the inner-most one
|
||||||
{
|
{
|
||||||
@ -2385,8 +2395,9 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
This procedure treats GROUP BY and SELECT as one namespace for column
|
|
||||||
references in HAVING.
|
This procedure treats GROUP BY and SELECT clauses as one namespace for
|
||||||
|
column references in HAVING.
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
TRUE if error
|
TRUE if error
|
||||||
@ -2398,9 +2409,10 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
DBUG_ASSERT(fixed == 0);
|
DBUG_ASSERT(fixed == 0);
|
||||||
uint counter;
|
uint counter;
|
||||||
SELECT_LEX *current_sel= thd->lex->current_select;
|
SELECT_LEX *current_sel= thd->lex->current_select;
|
||||||
List<Item> *search_namespace= current_sel->get_item_list();
|
List<Item> *select_fields= current_sel->get_item_list();
|
||||||
bool is_having_field= current_sel->having_fix_field;
|
bool is_having_field= current_sel->having_fix_field;
|
||||||
Item **group_by_ref= NULL;
|
Item **group_by_ref= NULL;
|
||||||
|
bool ambiguous_fields= FALSE;
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
{
|
{
|
||||||
@ -2413,7 +2425,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
Search for a column or derived column named as 'this' in the SELECT
|
Search for a column or derived column named as 'this' in the SELECT
|
||||||
clause of current_select.
|
clause of current_select.
|
||||||
*/
|
*/
|
||||||
if (!(ref= find_item_in_list(this, *search_namespace, &counter,
|
if (!(ref= find_item_in_list(this, *select_fields, &counter,
|
||||||
REPORT_EXCEPT_NOT_FOUND)))
|
REPORT_EXCEPT_NOT_FOUND)))
|
||||||
return TRUE; /* Some error occurred. */
|
return TRUE; /* Some error occurred. */
|
||||||
|
|
||||||
@ -2422,20 +2434,22 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
{
|
{
|
||||||
group_by_ref= find_field_in_group_list(this, (ORDER*)
|
group_by_ref= find_field_in_group_list(this, (ORDER*)
|
||||||
current_sel->group_list.first);
|
current_sel->group_list.first);
|
||||||
|
|
||||||
/* Check if the fields found in SELECT and GROUP BY are the same field. */
|
/* Check if the fields found in SELECT and GROUP BY are the same field. */
|
||||||
if (group_by_ref && ref != (Item **) not_found_item &&
|
if (group_by_ref && ref != (Item **) not_found_item &&
|
||||||
!((*group_by_ref)->eq(*ref, 0)))
|
!((*group_by_ref)->eq(*ref, 0)))
|
||||||
{
|
{
|
||||||
my_printf_error(ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
|
ambiguous_fields= TRUE;
|
||||||
MYF(0), this->full_name(), current_thd->where);
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
return TRUE;
|
ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR),
|
||||||
|
this->full_name(), current_thd->where);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If we didn't find such a column in the current query, and if there is an
|
If we didn't find such a column in the current query, and if there is an
|
||||||
outer select, and this is not a derived table (which do not support the
|
outer select, and it is not a derived table (which do not support the
|
||||||
use of outer fields for now), search the outer select(s) for a column
|
use of outer fields for now), search the outer select(s) for a column
|
||||||
named as 'this'.
|
named as 'this'.
|
||||||
*/
|
*/
|
||||||
@ -2494,7 +2508,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
outer_sel->group_list.elements == 0)) &&
|
outer_sel->group_list.elements == 0)) &&
|
||||||
(tmp= find_field_in_tables(thd, this,
|
(tmp= find_field_in_tables(thd, this,
|
||||||
table_list, reference,
|
table_list, reference,
|
||||||
0, 1)) != not_found_field)
|
IGNORE_EXCEPT_NON_UNIQUE, TRUE)) !=
|
||||||
|
not_found_field)
|
||||||
{
|
{
|
||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
@ -2538,7 +2553,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Call to report error
|
// Call to report error
|
||||||
find_item_in_list(this, *search_namespace, &counter,
|
find_item_in_list(this, *select_fields, &counter,
|
||||||
REPORT_ALL_ERRORS);
|
REPORT_ALL_ERRORS);
|
||||||
}
|
}
|
||||||
ref= 0;
|
ref= 0;
|
||||||
@ -2588,7 +2603,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ref != (Item **) not_found_item)
|
if (ref != (Item **) not_found_item && !ambiguous_fields)
|
||||||
ref= current_sel->ref_pointer_array + counter;
|
ref= current_sel->ref_pointer_array + counter;
|
||||||
else if (group_by_ref)
|
else if (group_by_ref)
|
||||||
ref= group_by_ref;
|
ref= group_by_ref;
|
||||||
|
@ -650,8 +650,13 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var,
|
|||||||
rw_lock_t *var_mutex);
|
rw_lock_t *var_mutex);
|
||||||
extern const Field *not_found_field;
|
extern const Field *not_found_field;
|
||||||
extern const Field *view_ref_found;
|
extern const Field *view_ref_found;
|
||||||
|
|
||||||
|
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
|
||||||
|
IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
|
||||||
|
IGNORE_EXCEPT_NON_UNIQUE};
|
||||||
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||||
Item **ref, bool report_error,
|
Item **ref,
|
||||||
|
find_item_error_report_type report_error,
|
||||||
bool check_privileges);
|
bool check_privileges);
|
||||||
Field *
|
Field *
|
||||||
find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||||
@ -765,8 +770,6 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
|
|||||||
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
|
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
|
||||||
table_map read_tables, COND *conds, int *error,
|
table_map read_tables, COND *conds, int *error,
|
||||||
bool allow_null_cond= false);
|
bool allow_null_cond= false);
|
||||||
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
|
|
||||||
IGNORE_ERRORS};
|
|
||||||
extern const Item **not_found_item;
|
extern const Item **not_found_item;
|
||||||
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
|
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
|
||||||
find_item_error_report_type report_error);
|
find_item_error_report_type report_error);
|
||||||
|
@ -615,7 +615,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
|
|||||||
Item_field *field= new Item_field("mysql", "proc",
|
Item_field *field= new Item_field("mysql", "proc",
|
||||||
used_field->field_name);
|
used_field->field_name);
|
||||||
if (!(used_field->field= find_field_in_tables(thd, field, &tables,
|
if (!(used_field->field= find_field_in_tables(thd, field, &tables,
|
||||||
0, TRUE, 1)))
|
0, REPORT_ALL_ERRORS, 1)))
|
||||||
{
|
{
|
||||||
res= SP_INTERNAL_ERROR;
|
res= SP_INTERNAL_ERROR;
|
||||||
goto err_case1;
|
goto err_case1;
|
||||||
|
@ -2173,25 +2173,33 @@ Field *find_field_in_real_table(THD *thd, TABLE *table,
|
|||||||
find_field_in_tables()
|
find_field_in_tables()
|
||||||
thd Pointer to current thread structure
|
thd Pointer to current thread structure
|
||||||
item Field item that should be found
|
item Field item that should be found
|
||||||
tables Tables for scanning
|
tables Tables to be searched for item
|
||||||
ref if view field is found, pointer to view item will
|
ref If 'item' is resolved to a view field, ref is set to
|
||||||
be returned via this parameter
|
point to the found view field
|
||||||
report_error If FALSE then do not report error if item not found
|
report_error Degree of error reporting:
|
||||||
and return not_found_field
|
- IGNORE_ERRORS then do not report any error
|
||||||
|
- IGNORE_EXCEPT_NON_UNIQUE report only non-unique
|
||||||
|
fields, suppress all other errors
|
||||||
|
- REPORT_EXCEPT_NON_UNIQUE report all other errors
|
||||||
|
except when non-unique fields were found
|
||||||
|
- REPORT_ALL_ERRORS
|
||||||
check_privileges need to check privileges
|
check_privileges need to check privileges
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 Field is not found or field is not unique- error
|
0 No field was found, or the found field is not unique, or
|
||||||
message is reported
|
there are no sufficient access priviligaes for the
|
||||||
not_found_field Function was called with report_error == FALSE and
|
found field, or the field is qualified with non-existing
|
||||||
field was not found. no error message reported.
|
table.
|
||||||
view_ref_found view field is found, item passed through ref parameter
|
not_found_field The function was called with report_error ==
|
||||||
found field
|
(IGNORE_ERRORS || IGNORE_EXCEPT_NON_UNIQUE) and a
|
||||||
|
field was not found.
|
||||||
|
view_ref_found View field is found, item passed through ref parameter
|
||||||
|
found field If a item was resolved to some field
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Field *
|
Field *
|
||||||
find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||||
Item **ref, bool report_error,
|
Item **ref, find_item_error_report_type report_error,
|
||||||
bool check_privileges)
|
bool check_privileges)
|
||||||
{
|
{
|
||||||
Field *found=0;
|
Field *found=0;
|
||||||
@ -2268,8 +2276,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
return find;
|
return find;
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
item->full_name(),thd->where);
|
report_error == IGNORE_EXCEPT_NON_UNIQUE)
|
||||||
|
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
||||||
|
item->full_name(),thd->where);
|
||||||
return (Field*) 0;
|
return (Field*) 0;
|
||||||
}
|
}
|
||||||
found=find;
|
found=find;
|
||||||
@ -2278,7 +2288,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
return found;
|
return found;
|
||||||
if (!found_table && report_error)
|
if (!found_table && (report_error == REPORT_ALL_ERRORS ||
|
||||||
|
report_error == REPORT_EXCEPT_NON_UNIQUE))
|
||||||
{
|
{
|
||||||
char buff[NAME_LEN*2+1];
|
char buff[NAME_LEN*2+1];
|
||||||
if (db && db[0])
|
if (db && db[0])
|
||||||
@ -2286,28 +2297,30 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
|
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
|
||||||
table_name=buff;
|
table_name=buff;
|
||||||
}
|
}
|
||||||
if (report_error)
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
{
|
report_error == REPORT_EXCEPT_NON_UNIQUE)
|
||||||
my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
|
my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
|
||||||
table_name, thd->where);
|
table_name, thd->where);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return (Field*) not_found_field;
|
return (Field*) not_found_field;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (report_error)
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
|
report_error == REPORT_EXCEPT_NON_UNIQUE)
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||||
item->full_name(),thd->where);
|
item->full_name(),thd->where);
|
||||||
else
|
else
|
||||||
return (Field*) not_found_field;
|
return (Field*) not_found_field;
|
||||||
return (Field*) 0;
|
return (Field*) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allow_rowid= tables && !tables->next_local; // Only one table
|
bool allow_rowid= tables && !tables->next_local; // Only one table
|
||||||
for (; tables ; tables= tables->next_local)
|
for (; tables ; tables= tables->next_local)
|
||||||
{
|
{
|
||||||
if (!tables->table)
|
if (!tables->table)
|
||||||
{
|
{
|
||||||
if (report_error)
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
|
report_error == REPORT_EXCEPT_NON_UNIQUE)
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||||
item->full_name(),thd->where);
|
item->full_name(),thd->where);
|
||||||
return (Field*) not_found_field;
|
return (Field*) not_found_field;
|
||||||
@ -2332,8 +2345,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
{
|
{
|
||||||
if (!thd->where) // Returns first found
|
if (!thd->where) // Returns first found
|
||||||
break;
|
break;
|
||||||
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
name,thd->where);
|
report_error == IGNORE_EXCEPT_NON_UNIQUE)
|
||||||
|
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
||||||
|
name,thd->where);
|
||||||
return (Field*) 0;
|
return (Field*) 0;
|
||||||
}
|
}
|
||||||
found=field;
|
found=field;
|
||||||
@ -2341,7 +2356,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
return found;
|
return found;
|
||||||
if (report_error)
|
if (report_error == REPORT_ALL_ERRORS ||
|
||||||
|
report_error == REPORT_EXCEPT_NON_UNIQUE)
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
|
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
|
||||||
MYF(0), item->full_name(), thd->where);
|
MYF(0), item->full_name(), thd->where);
|
||||||
else
|
else
|
||||||
@ -2377,7 +2393,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
|||||||
found field
|
found field
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Special Item pointer for find_item_in_list returning
|
/* Special Item pointer to serve as a return value from find_item_in_list(). */
|
||||||
const Item **not_found_item= (const Item**) 0x1;
|
const Item **not_found_item= (const Item**) 0x1;
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
|
|||||||
Item_field *field= new Item_field("mysql", find_fields->table_name,
|
Item_field *field= new Item_field("mysql", find_fields->table_name,
|
||||||
find_fields->field_name);
|
find_fields->field_name);
|
||||||
if (!(find_fields->field= find_field_in_tables(thd, field, tables,
|
if (!(find_fields->field= find_field_in_tables(thd, field, tables,
|
||||||
0, TRUE, 1)))
|
0, REPORT_ALL_ERRORS, 1)))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
@ -11115,24 +11115,53 @@ cp_buffer_from_ref(TABLE_REF *ref)
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find order/group item in requested columns and change the item to point at
|
Resolve an ORDER BY or GROUP BY column reference.
|
||||||
it. If item doesn't exists, add it first in the field list
|
|
||||||
Return 0 if ok.
|
SYNOPSIS
|
||||||
|
find_order_in_list()
|
||||||
|
thd [in] Pointer to current thread structure
|
||||||
|
ref_pointer_array [in/out] All select, group and order by fields
|
||||||
|
tables [in] List of tables to search in (usually FROM clause)
|
||||||
|
order [in] Column reference to be resolved
|
||||||
|
fields [in] List of fields to search in (usually SELECT list)
|
||||||
|
all_fields [in/out] All select, group and order by fields
|
||||||
|
is_group_field [in] True if order is a GROUP field, false if
|
||||||
|
ORDER by field
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Given a column reference (represented by 'order') from a GROUP BY or ORDER
|
||||||
|
BY clause, find the actual column it represents. If the column being
|
||||||
|
resolved is from the GROUP BY clause, the procedure searches the SELECT
|
||||||
|
list 'fields' and the columns in the FROM list 'tables'. If 'order' is from
|
||||||
|
the ORDER BY clause, only the SELECT list is being searched.
|
||||||
|
|
||||||
|
If 'order' is resolved to an Item, then order->item is set to the found
|
||||||
|
Item. If there is no item for the found column (that is, it was resolved
|
||||||
|
into a table field), order->item is 'fixed' and is added to all_fields and
|
||||||
|
ref_pointer_array.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 if ok
|
||||||
|
1 if error occurred
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
find_order_in_list(THD *thd, Item **ref_pointer_array,
|
find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||||
TABLE_LIST *tables,ORDER *order, List<Item> &fields,
|
ORDER *order, List<Item> &fields, List<Item> &all_fields,
|
||||||
List<Item> &all_fields)
|
bool is_group_field)
|
||||||
{
|
{
|
||||||
Item *itemptr=*order->item;
|
Item *order_item=*order->item; /* The item from the GROUP/ORDER caluse. */
|
||||||
if (itemptr->type() == Item::INT_ITEM)
|
Item::Type order_item_type;
|
||||||
|
Item **select_item; /* The corresponding item from the SELECT clause. */
|
||||||
|
Field *from_field; /* The corresponding field from the FROM clause. */
|
||||||
|
|
||||||
|
if (order_item->type() == Item::INT_ITEM)
|
||||||
{ /* Order by position */
|
{ /* Order by position */
|
||||||
uint count= (uint) itemptr->val_int();
|
uint count= (uint) order_item->val_int();
|
||||||
if (!count || count > fields.elements)
|
if (!count || count > fields.elements)
|
||||||
{
|
{
|
||||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
||||||
MYF(0),itemptr->full_name(),
|
MYF(0),order_item->full_name(),
|
||||||
thd->where);
|
thd->where);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -11142,17 +11171,47 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
|
|||||||
order->counter_used= 1;
|
order->counter_used= 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Lookup the current GROUP/ORDER field in the SELECT clause. */
|
||||||
uint counter;
|
uint counter;
|
||||||
Item **item= find_item_in_list(itemptr, fields, &counter,
|
select_item= find_item_in_list(order_item, fields, &counter,
|
||||||
REPORT_EXCEPT_NOT_FOUND);
|
REPORT_EXCEPT_NOT_FOUND);
|
||||||
if (!item)
|
if (!select_item)
|
||||||
return 1;
|
return 1; /* Some error occured. */
|
||||||
|
|
||||||
if (item != (Item **)not_found_item)
|
|
||||||
|
/* Check whether the resolved field is not ambiguos. */
|
||||||
|
if (select_item != not_found_item)
|
||||||
{
|
{
|
||||||
order->item= ref_pointer_array + counter;
|
/* Lookup the current GROUP field in the FROM clause. */
|
||||||
order->in_field_list=1;
|
order_item_type= order_item->type();
|
||||||
return 0;
|
if (is_group_field &&
|
||||||
|
order_item_type == Item::FIELD_ITEM || order_item_type == Item::REF_ITEM)
|
||||||
|
{
|
||||||
|
Item **view_ref= NULL;
|
||||||
|
from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
|
||||||
|
view_ref, IGNORE_ERRORS, TRUE);
|
||||||
|
if(!from_field)
|
||||||
|
from_field= (Field*) not_found_field;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
from_field= (Field*) not_found_field;
|
||||||
|
|
||||||
|
if (from_field == not_found_field ||
|
||||||
|
from_field && from_field != view_ref_found &&
|
||||||
|
(*select_item)->type() == Item::FIELD_ITEM &&
|
||||||
|
((Item_field*) (*select_item))->field->eq(from_field))
|
||||||
|
/*
|
||||||
|
If there is no such field in the FROM clause, or it is the same field as
|
||||||
|
the one found in the SELECT clause, then use the Item created for the
|
||||||
|
SELECT field. As a result if there was a derived field that 'shadowed'
|
||||||
|
a table field with the same name, the table field will be chosen over
|
||||||
|
the derived field.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
order->item= ref_pointer_array + counter;
|
||||||
|
order->in_field_list=1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
order->in_field_list=0;
|
order->in_field_list=0;
|
||||||
@ -11187,7 +11246,7 @@ int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
|||||||
for (; order; order=order->next)
|
for (; order; order=order->next)
|
||||||
{
|
{
|
||||||
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
|
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
|
||||||
all_fields))
|
all_fields, FALSE))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -11239,7 +11298,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
|||||||
for (; order; order=order->next)
|
for (; order; order=order->next)
|
||||||
{
|
{
|
||||||
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
|
if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
|
||||||
all_fields))
|
all_fields, TRUE))
|
||||||
return 1;
|
return 1;
|
||||||
(*order->item)->marker=1; /* Mark found */
|
(*order->item)->marker=1; /* Mark found */
|
||||||
if ((*order->item)->with_sum_func)
|
if ((*order->item)->with_sum_func)
|
||||||
|
Reference in New Issue
Block a user