mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
Merge epotemkin@bk-internal.mysql.com:/home/bk/mysql-5.0-opt
into moonbone.local:/mnt/gentoo64/work/27321-bug-5.0-opt-mysql
This commit is contained in:
commit
922a5a969c
8 changed files with 245 additions and 87 deletions
|
@ -48,7 +48,7 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'a' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1276 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1276 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1
|
||||
Note 1003 select 1 AS `1` from (select 1 AS `a`) `b` having ((select '1' AS `a`) = 1)
|
||||
SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
|
||||
|
@ -330,7 +330,7 @@ patient_uq clinic_uq
|
|||
explain extended select * from t6 where exists (select * from t7 where uq = clinic_uq);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t6 ALL NULL NULL NULL NULL 4 Using where
|
||||
2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 t6.clinic_uq 1 Using where; Using index
|
||||
2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 test.t6.clinic_uq 1 Using index
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'test.t6.clinic_uq' of SELECT #2 was resolved in SELECT #1
|
||||
Note 1003 select `test`.`t6`.`patient_uq` AS `patient_uq`,`test`.`t6`.`clinic_uq` AS `clinic_uq` from `test`.`t6` where exists(select 1 AS `Not_used` from `test`.`t7` where (`test`.`t7`.`uq` = `test`.`t6`.`clinic_uq`))
|
||||
|
@ -1741,7 +1741,7 @@ Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`text` AS `text` from `tes
|
|||
explain extended select * from t1 as tt where not exists (select id from t1 where id < 8 and (id = tt.id or id is null) having id is not null);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY tt ALL NULL NULL NULL NULL 12 Using where
|
||||
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 tt.id 1 Using where; Using index
|
||||
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 test.tt.id 1 Using where; Using index
|
||||
Warnings:
|
||||
Note 1276 Field or reference 'test.tt.id' of SELECT #2 was resolved in SELECT #1
|
||||
Note 1003 select `test`.`tt`.`id` AS `id`,`test`.`tt`.`text` AS `text` from `test`.`t1` `tt` where (not(exists(select `test`.`t1`.`id` AS `id` from `test`.`t1` where ((`test`.`t1`.`id` < 8) and (`test`.`t1`.`id` = `test`.`tt`.`id`)) having (`test`.`t1`.`id` is not null))))
|
||||
|
@ -3924,6 +3924,70 @@ c a (SELECT GROUP_CONCAT(COUNT(a)+1) FROM t2 WHERE m = a)
|
|||
3 3 4
|
||||
1 4 2,2
|
||||
DROP table t1,t2;
|
||||
CREATE TABLE t1 (a int, b INT, d INT, c CHAR(10) NOT NULL, PRIMARY KEY (a, b));
|
||||
INSERT INTO t1 VALUES (1,1,0,'a'), (1,2,0,'b'), (1,3,0,'c'), (1,4,0,'d'),
|
||||
(1,5,0,'e'), (2,1,0,'f'), (2,2,0,'g'), (2,3,0,'h'), (3,4,0,'i'), (3,3,0,'j'),
|
||||
(3,2,0,'k'), (3,1,0,'l'), (1,9,0,'m'), (1,0,10,'n'), (2,0,5,'o'), (3,0,7,'p');
|
||||
SELECT a, MAX(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b + 0)) as test
|
||||
FROM t1 GROUP BY a;
|
||||
a MAX(b) test
|
||||
1 9 m
|
||||
2 3 h
|
||||
3 4 i
|
||||
SELECT a x, MAX(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE x=t.a AND t.b=MAX(t1.b + 0)) as test
|
||||
FROM t1 GROUP BY a;
|
||||
x MAX(b) test
|
||||
1 9 m
|
||||
2 3 h
|
||||
3 4 i
|
||||
SELECT a, AVG(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b)) AS test
|
||||
FROM t1 WHERE t1.d=0 GROUP BY a;
|
||||
a AVG(b) test
|
||||
1 4.0000 d
|
||||
2 2.0000 g
|
||||
3 2.5000 NULL
|
||||
SELECT tt.a,
|
||||
(SELECT (SELECT c FROM t1 as t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1) FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test
|
||||
FROM t1 as tt;
|
||||
a test
|
||||
1 n
|
||||
1 n
|
||||
1 n
|
||||
1 n
|
||||
1 n
|
||||
1 n
|
||||
1 n
|
||||
2 o
|
||||
2 o
|
||||
2 o
|
||||
2 o
|
||||
3 p
|
||||
3 p
|
||||
3 p
|
||||
3 p
|
||||
3 p
|
||||
SELECT tt.a,
|
||||
(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1)
|
||||
FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test
|
||||
FROM t1 as tt GROUP BY tt.a;
|
||||
a test
|
||||
1 n
|
||||
2 o
|
||||
3 p
|
||||
SELECT tt.a, MAX(
|
||||
(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1)
|
||||
FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1)) as test
|
||||
FROM t1 as tt GROUP BY tt.a;
|
||||
a test
|
||||
1 n
|
||||
2 o
|
||||
3 p
|
||||
CREATE TABLE t1 (a int, b int);
|
||||
INSERT INTO t1 VALUES (2,22),(1,11),(2,22);
|
||||
SELECT a FROM t1 WHERE (SELECT COUNT(b) FROM DUAL) > 0 GROUP BY a;
|
||||
|
|
|
@ -432,7 +432,7 @@ alter table t1 add index idx(oref,ie);
|
|||
explain select oref, a, a in (select ie from t1 where oref=t2.oref) Z from t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 7
|
||||
2 DEPENDENT SUBQUERY t1 ref_or_null idx idx 10 t2.oref,func 4 Using where; Using index; Full scan on NULL key
|
||||
2 DEPENDENT SUBQUERY t1 ref_or_null idx idx 10 test.t2.oref,func 4 Using where; Using index; Full scan on NULL key
|
||||
select oref, a, a in (select ie from t1 where oref=t2.oref) Z from t2;
|
||||
oref a Z
|
||||
ee NULL NULL
|
||||
|
@ -457,7 +457,7 @@ group by grp having min(ie) > 1) Z
|
|||
from t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 7
|
||||
2 DEPENDENT SUBQUERY t1 ref idx idx 5 t2.oref 2 Using where; Using temporary; Using filesort
|
||||
2 DEPENDENT SUBQUERY t1 ref idx idx 5 test.t2.oref 2 Using where; Using temporary; Using filesort
|
||||
select oref, a,
|
||||
a in (select min(ie) from t1 where oref=t2.oref
|
||||
group by grp having min(ie) > 1) Z
|
||||
|
|
|
@ -2783,6 +2783,41 @@ SELECT COUNT(*) c, a,
|
|||
|
||||
DROP table t1,t2;
|
||||
|
||||
#
|
||||
# Bug#27321: Wrong subquery result in a grouping select
|
||||
#
|
||||
CREATE TABLE t1 (a int, b INT, d INT, c CHAR(10) NOT NULL, PRIMARY KEY (a, b));
|
||||
INSERT INTO t1 VALUES (1,1,0,'a'), (1,2,0,'b'), (1,3,0,'c'), (1,4,0,'d'),
|
||||
(1,5,0,'e'), (2,1,0,'f'), (2,2,0,'g'), (2,3,0,'h'), (3,4,0,'i'), (3,3,0,'j'),
|
||||
(3,2,0,'k'), (3,1,0,'l'), (1,9,0,'m'), (1,0,10,'n'), (2,0,5,'o'), (3,0,7,'p');
|
||||
|
||||
SELECT a, MAX(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b + 0)) as test
|
||||
FROM t1 GROUP BY a;
|
||||
SELECT a x, MAX(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE x=t.a AND t.b=MAX(t1.b + 0)) as test
|
||||
FROM t1 GROUP BY a;
|
||||
SELECT a, AVG(b),
|
||||
(SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b)) AS test
|
||||
FROM t1 WHERE t1.d=0 GROUP BY a;
|
||||
|
||||
SELECT tt.a,
|
||||
(SELECT (SELECT c FROM t1 as t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1) FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test
|
||||
FROM t1 as tt;
|
||||
|
||||
SELECT tt.a,
|
||||
(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1)
|
||||
FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1) as test
|
||||
FROM t1 as tt GROUP BY tt.a;
|
||||
|
||||
SELECT tt.a, MAX(
|
||||
(SELECT (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.d=MAX(t1.b + tt.a)
|
||||
LIMIT 1)
|
||||
FROM t1 WHERE t1.a=tt.a GROUP BY a LIMIT 1)) as test
|
||||
FROM t1 as tt GROUP BY tt.a;
|
||||
|
||||
#
|
||||
# Bug #27348: SET FUNCTION used in a subquery from WHERE condition
|
||||
#
|
||||
|
|
|
@ -507,9 +507,6 @@ SELECT a, MAX(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=MAX(t1.b))
|
|||
SELECT * FROM t1 GROUP by t1.a
|
||||
HAVING (MAX(t1.b) > (SELECT MAX(t2.b) FROM t2 WHERE t2.c < t1.c
|
||||
HAVING MAX(t2.b+t1.a) < 10));
|
||||
#FIXME: Enable this test after fixing bug #27321
|
||||
#SELECT a, AVG(b), (SELECT t.c FROM t1 AS t WHERE t1.a=t.a AND t.b=AVG(t1.b))
|
||||
# AS test FROM t1 GROUP BY a;
|
||||
|
||||
SELECT a,b,c FROM t1 WHERE b in (9,3,4) ORDER BY b,c;
|
||||
|
||||
|
|
83
sql/item.cc
83
sql/item.cc
|
@ -1610,7 +1610,7 @@ void Item_ident_for_show::make_field(Send_field *tmp_field)
|
|||
Item_field::Item_field(Field *f)
|
||||
:Item_ident(0, NullS, *f->table_name, f->field_name),
|
||||
item_equal(0), no_const_subst(0),
|
||||
have_privileges(0), any_privileges(0), fixed_as_field(0)
|
||||
have_privileges(0), any_privileges(0)
|
||||
{
|
||||
set_field(f);
|
||||
/*
|
||||
|
@ -1624,7 +1624,7 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
|
|||
Field *f)
|
||||
:Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name),
|
||||
item_equal(0), no_const_subst(0),
|
||||
have_privileges(0), any_privileges(0), fixed_as_field(0)
|
||||
have_privileges(0), any_privileges(0)
|
||||
{
|
||||
/*
|
||||
We always need to provide Item_field with a fully qualified field
|
||||
|
@ -1663,7 +1663,7 @@ Item_field::Item_field(Name_resolution_context *context_arg,
|
|||
const char *field_name_arg)
|
||||
:Item_ident(context_arg, db_arg,table_name_arg,field_name_arg),
|
||||
field(0), result_field(0), item_equal(0), no_const_subst(0),
|
||||
have_privileges(0), any_privileges(0), fixed_as_field(0)
|
||||
have_privileges(0), any_privileges(0)
|
||||
{
|
||||
SELECT_LEX *select= current_thd->lex->current_select;
|
||||
collation.set(DERIVATION_IMPLICIT);
|
||||
|
@ -1679,8 +1679,7 @@ Item_field::Item_field(THD *thd, Item_field *item)
|
|||
item_equal(item->item_equal),
|
||||
no_const_subst(item->no_const_subst),
|
||||
have_privileges(item->have_privileges),
|
||||
any_privileges(item->any_privileges),
|
||||
fixed_as_field(item->fixed_as_field)
|
||||
any_privileges(item->any_privileges)
|
||||
{
|
||||
collation.set(DERIVATION_IMPLICIT);
|
||||
}
|
||||
|
@ -3447,6 +3446,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
Item **ref= (Item **) not_found_item;
|
||||
SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select;
|
||||
Name_resolution_context *outer_context= 0;
|
||||
SELECT_LEX *select;
|
||||
/* Currently derived tables cannot be correlated */
|
||||
if (current_sel->master_unit()->first_select()->linkage !=
|
||||
DERIVED_TABLE_TYPE)
|
||||
|
@ -3455,7 +3455,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
outer_context;
|
||||
outer_context= outer_context->outer_context)
|
||||
{
|
||||
SELECT_LEX *select= outer_context->select_lex;
|
||||
select= outer_context->select_lex;
|
||||
Item_subselect *prev_subselect_item=
|
||||
last_checked_context->select_lex->master_unit()->item;
|
||||
last_checked_context= outer_context;
|
||||
|
@ -3498,45 +3498,28 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
}
|
||||
if (*from_field != view_ref_found)
|
||||
{
|
||||
|
||||
prev_subselect_item->used_tables_cache|= (*from_field)->table->map;
|
||||
prev_subselect_item->const_item_cache= 0;
|
||||
set_field(*from_field);
|
||||
if (!last_checked_context->select_lex->having_fix_field &&
|
||||
!fixed_as_field)
|
||||
select->group_list.elements)
|
||||
{
|
||||
Item_outer_ref *rf;
|
||||
Query_arena *arena= 0, backup;
|
||||
/*
|
||||
Each outer field is replaced for an Item_outer_ref object.
|
||||
This is done in order to get correct results when the outer
|
||||
select employs a temporary table.
|
||||
The original fields are saved in the inner_fields_list of the
|
||||
outer select. This list is created by the following reasons:
|
||||
1. We can't add field items to the outer select list directly
|
||||
because the outer select hasn't been fully fixed yet.
|
||||
2. We need a location to refer to in the Item_ref object
|
||||
so the inner_fields_list is used as such temporary
|
||||
reference storage.
|
||||
The new Item_outer_ref object replaces the original field and is
|
||||
also saved in the inner_refs_list of the outer select. Here
|
||||
it is only created. It can be fixed only after the original
|
||||
field has been fixed and this is done in the fix_inner_refs()
|
||||
function.
|
||||
If an outer field is resolved in a grouping select then it
|
||||
is replaced for an Item_outer_ref object. Otherwise an
|
||||
Item_field object is used.
|
||||
The new Item_outer_ref object is saved in the inner_refs_list of
|
||||
the outer select. Here it is only created. It can be fixed only
|
||||
after the original field has been fixed and this is done in the
|
||||
fix_inner_refs() function.
|
||||
*/
|
||||
set_field(*from_field);
|
||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||
rf= new Item_outer_ref(context, this);
|
||||
if (!rf)
|
||||
{
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
;
|
||||
if (!(rf= new Item_outer_ref(context, this)))
|
||||
return -1;
|
||||
}
|
||||
*reference= rf;
|
||||
thd->change_item_tree(reference, rf);
|
||||
select->inner_refs_list.push_back(rf);
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
fixed_as_field= 1;
|
||||
rf->in_sum_func= thd->lex->in_sum_func;
|
||||
}
|
||||
if (thd->lex->in_sum_func &&
|
||||
thd->lex->in_sum_func->nest_level ==
|
||||
|
@ -3642,11 +3625,20 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||
rf= (place == IN_HAVING ?
|
||||
new Item_ref(context, ref, (char*) table_name,
|
||||
(char*) field_name, alias_name_used) :
|
||||
(!select->group_list.elements ?
|
||||
new Item_direct_ref(context, ref, (char*) table_name,
|
||||
(char*) field_name, alias_name_used));
|
||||
(char*) field_name, alias_name_used) :
|
||||
new Item_outer_ref(context, ref, (char*) table_name,
|
||||
(char*) field_name, alias_name_used)));
|
||||
*ref= save;
|
||||
if (!rf)
|
||||
return -1;
|
||||
|
||||
if (place != IN_HAVING && select->group_list.elements)
|
||||
{
|
||||
outer_context->select_lex->inner_refs_list.push_back((Item_outer_ref*)rf);
|
||||
((Item_outer_ref*)rf)->in_sum_func= thd->lex->in_sum_func;
|
||||
}
|
||||
thd->change_item_tree(reference, rf);
|
||||
/*
|
||||
rf is Item_ref => never substitute other items (in this case)
|
||||
|
@ -5550,16 +5542,19 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
|
|||
|
||||
bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
|
||||
{
|
||||
DBUG_ASSERT(*ref);
|
||||
/* outer_field->check_cols() will be made in Item_direct_ref::fix_fields */
|
||||
outer_field->fixed_as_field= 1;
|
||||
if (!outer_field->fixed &&
|
||||
(outer_field->fix_fields(thd, reference)))
|
||||
bool err;
|
||||
/* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */
|
||||
if ((*ref) && !(*ref)->fixed && ((*ref)->fix_fields(thd, reference)))
|
||||
return TRUE;
|
||||
table_name= outer_field->table_name;
|
||||
return Item_direct_ref::fix_fields(thd, reference);
|
||||
err= Item_direct_ref::fix_fields(thd, reference);
|
||||
if (!outer_ref)
|
||||
outer_ref= *ref;
|
||||
if ((*ref)->type() == Item::FIELD_ITEM)
|
||||
table_name= ((Item_field*)outer_ref)->table_name;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compare two view column references for equality.
|
||||
|
||||
|
|
44
sql/item.h
44
sql/item.h
|
@ -1220,7 +1220,6 @@ public:
|
|||
uint have_privileges;
|
||||
/* field need any privileges (for VIEW creation) */
|
||||
bool any_privileges;
|
||||
bool fixed_as_field;
|
||||
Item_field(Name_resolution_context *context_arg,
|
||||
const char *db_arg,const char *table_name_arg,
|
||||
const char *field_name_arg);
|
||||
|
@ -1978,30 +1977,49 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
Class for outer fields.
|
||||
An object of this class is created when the select where the outer field was
|
||||
resolved is a grouping one. After it has been fixed the ref field will point
|
||||
to either an Item_ref or an Item_direct_ref object which will be used to
|
||||
access the field.
|
||||
See also comments for the fix_inner_refs() and the
|
||||
Item_field::fix_outer_field() functions.
|
||||
*/
|
||||
|
||||
class Item_sum;
|
||||
class Item_outer_ref :public Item_direct_ref
|
||||
{
|
||||
public:
|
||||
Item_field *outer_field;
|
||||
Item *outer_ref;
|
||||
/* The aggregate function under which this outer ref is used, if any. */
|
||||
Item_sum *in_sum_func;
|
||||
/*
|
||||
TRUE <=> that the outer_ref is already present in the select list
|
||||
of the outer select.
|
||||
*/
|
||||
bool found_in_select_list;
|
||||
Item_outer_ref(Name_resolution_context *context_arg,
|
||||
Item_field *outer_field_arg)
|
||||
:Item_direct_ref(context_arg, 0, outer_field_arg->table_name,
|
||||
outer_field_arg->field_name),
|
||||
outer_field(outer_field_arg)
|
||||
outer_field_arg->field_name),
|
||||
outer_ref(outer_field_arg), in_sum_func(0),
|
||||
found_in_select_list(0)
|
||||
{
|
||||
ref= (Item**)&outer_field;
|
||||
ref= &outer_ref;
|
||||
set_properties();
|
||||
fixed= 0;
|
||||
}
|
||||
void cleanup()
|
||||
{
|
||||
ref= (Item**)&outer_field;
|
||||
fixed= 0;
|
||||
Item_direct_ref::cleanup();
|
||||
outer_field->cleanup();
|
||||
}
|
||||
Item_outer_ref(Name_resolution_context *context_arg, Item **item,
|
||||
const char *table_name_arg, const char *field_name_arg,
|
||||
bool alias_name_used_arg)
|
||||
:Item_direct_ref(context_arg, item, table_name_arg, field_name_arg,
|
||||
alias_name_used_arg),
|
||||
outer_ref(0), in_sum_func(0), found_in_select_list(1)
|
||||
{}
|
||||
void save_in_result_field(bool no_conversions)
|
||||
{
|
||||
outer_field->save_org_in_field(result_field);
|
||||
outer_ref->save_org_in_field(result_field);
|
||||
}
|
||||
bool fix_fields(THD *, Item **);
|
||||
table_map used_tables() const
|
||||
|
|
|
@ -278,15 +278,30 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
|
|||
ref_pointer_array Array of references to Items used in current select
|
||||
|
||||
DESCRIPTION
|
||||
The function fixes fields referenced from inner selects and
|
||||
also fixes references (Item_ref objects) to these fields. Each field
|
||||
is fixed as a usual hidden field of the current select - it is added
|
||||
to the all_fields list and the pointer to it is saved in the
|
||||
ref_pointer_array if latter is provided.
|
||||
After the field has been fixed we proceed with fixing references
|
||||
(Item_ref objects) to this field from inner subqueries. If the
|
||||
ref_pointer_array is provided then Item_ref objects is set to
|
||||
reference element in that array with the pointer to the field.
|
||||
The function serves 3 purposes - adds fields referenced from inner
|
||||
selects to the current select list, resolves which class to use
|
||||
to access referenced item (Item_ref of Item_direct_ref) and fixes
|
||||
references (Item_ref objects) to these fields.
|
||||
|
||||
If a field isn't already in the select list and the ref_pointer_array
|
||||
is provided then it is added to the all_fields list and the pointer to
|
||||
it is saved in the ref_pointer_array.
|
||||
|
||||
The class to access the outer field is determined by the following rules:
|
||||
1. If the outer field isn't used under an aggregate function
|
||||
then the Item_ref class should be used.
|
||||
2. If the outer field is used under an aggregate function and this
|
||||
function is aggregated in the select where the outer field was
|
||||
resolved or in some more inner select then the Item_direct_ref
|
||||
class should be used.
|
||||
The resolution is done here and not at the fix_fields() stage as
|
||||
it can be done only after sum functions are fixed and pulled up to
|
||||
selects where they are have to be aggregated.
|
||||
When the class is chosen it substitutes the original field in the
|
||||
Item_outer_ref object.
|
||||
|
||||
After this we proceed with fixing references (Item_outer_ref objects) to
|
||||
this field from inner subqueries.
|
||||
|
||||
RETURN
|
||||
TRUE an error occured
|
||||
|
@ -299,33 +314,64 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
|
|||
{
|
||||
Item_outer_ref *ref;
|
||||
bool res= FALSE;
|
||||
bool direct_ref= FALSE;
|
||||
|
||||
List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
|
||||
while ((ref= ref_it++))
|
||||
{
|
||||
Item_field *item= ref->outer_field;
|
||||
Item *item= ref->outer_ref;
|
||||
Item **item_ref= ref->ref;
|
||||
Item_ref *new_ref;
|
||||
/*
|
||||
TODO: this field item already might be present in the select list.
|
||||
In this case instead of adding new field item we could use an
|
||||
existing one. The change will lead to less operations for copying fields,
|
||||
smaller temporary tables and less data passed through filesort.
|
||||
*/
|
||||
if (ref_pointer_array)
|
||||
if (ref_pointer_array && !ref->found_in_select_list)
|
||||
{
|
||||
int el= all_fields.elements;
|
||||
ref_pointer_array[el]= (Item*)item;
|
||||
ref_pointer_array[el]= item;
|
||||
/* Add the field item to the select list of the current select. */
|
||||
all_fields.push_front((Item*)item);
|
||||
all_fields.push_front(item);
|
||||
/*
|
||||
If it's needed reset each Item_ref item that refers this field with
|
||||
a new reference taken from ref_pointer_array.
|
||||
*/
|
||||
ref->ref= ref_pointer_array + el;
|
||||
item_ref= ref_pointer_array + el;
|
||||
}
|
||||
if (!ref->fixed && ref->fix_fields(thd, 0))
|
||||
|
||||
if (ref->in_sum_func)
|
||||
{
|
||||
res= TRUE;
|
||||
break;
|
||||
Item_sum *sum_func;
|
||||
if (ref->in_sum_func->nest_level > select->nest_level)
|
||||
direct_ref= TRUE;
|
||||
else
|
||||
{
|
||||
for (sum_func= ref->in_sum_func; sum_func &&
|
||||
sum_func->aggr_level >= select->nest_level;
|
||||
sum_func= sum_func->in_sum_func)
|
||||
{
|
||||
if (sum_func->aggr_level == select->nest_level)
|
||||
{
|
||||
direct_ref= TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new_ref= direct_ref ?
|
||||
new Item_direct_ref(ref->context, item_ref, ref->field_name,
|
||||
ref->table_name, ref->alias_name_used) :
|
||||
new Item_ref(ref->context, item_ref, ref->field_name,
|
||||
ref->table_name, ref->alias_name_used);
|
||||
if (!new_ref)
|
||||
return TRUE;
|
||||
ref->outer_ref= new_ref;
|
||||
ref->ref= &ref->outer_ref;
|
||||
|
||||
if (!ref->fixed && ref->fix_fields(thd, 0))
|
||||
return TRUE;
|
||||
thd->used_tables|= item->used_tables();
|
||||
}
|
||||
return res;
|
||||
|
@ -478,10 +524,6 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||
if (having && having->with_sum_func)
|
||||
having->split_sum_func2(thd, ref_pointer_array, all_fields,
|
||||
&having, TRUE);
|
||||
if (select_lex->inner_refs_list.elements &&
|
||||
fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (select_lex->inner_sum_func_list)
|
||||
{
|
||||
Item_sum *end=select_lex->inner_sum_func_list;
|
||||
|
@ -494,6 +536,10 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||
} while (item_sum != end);
|
||||
}
|
||||
|
||||
if (select_lex->inner_refs_list.elements &&
|
||||
fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
|
@ -5214,7 +5260,9 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
|
|||
}
|
||||
else if (keyuse->val->type() == Item::FIELD_ITEM ||
|
||||
(keyuse->val->type() == Item::REF_ITEM &&
|
||||
((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF) )
|
||||
((Item_ref*)keyuse->val)->ref_type() == Item_ref::OUTER_REF &&
|
||||
(*(Item_ref**)((Item_ref*)keyuse->val)->ref)->ref_type() ==
|
||||
Item_ref::DIRECT_REF) )
|
||||
return new store_key_field(thd,
|
||||
key_part->field,
|
||||
key_buff + maybe_null,
|
||||
|
|
|
@ -743,6 +743,7 @@ bool st_select_lex::cleanup()
|
|||
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
||||
}
|
||||
non_agg_fields.empty();
|
||||
inner_refs_list.empty();
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue