| Bug #23800 | Correlated sub query returning incorrect results when operated upon | ||
|---|---|---|---|
| Submitted: | 31 Oct 2006 10:47 | Modified: | 6 Mar 2007 19:30 |
| Reporter: | Andrew Rose | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
| Version: | 5.0.26-27/4.1BK/5.0BK/5.1BK | OS: | GNU/Linux (Archlinux) |
| Assigned to: | Evgeny Potemkin | CPU Architecture: | Any |
| Tags: | correlated sub query operated upon incorrect results | ||
[31 Oct 2006 19:16]
MySQL Verification Team
Thank you for the bug report. Verfied as described.
mysql> select ((select sum(c.weight) from slips as b, events as c where b.pevent = c.id
-> and b.studentid = a.id) * count(d.id)) as BI from students as a, slips as d
-> where
-> a.id = d.studentid group by a.id;
+------+
| BI |
+------+
| 48 |
| 48 |
| 48 |
+------+
3 rows in set (0.01 sec)
mysql> select version();
+--------------+
| version() |
+--------------+
| 5.0.29-debug |
+--------------+
1 row in set (0.00 sec)
[30 Jan 2007 22:10]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/19049 ChangeSet@1.2386, 2007-01-31 01:07:38+03:00, evgen@moonbone.local +12 -0 Bug#23800: Correlated sub query returning incorrect results when operated upon. All outer fields in a subquery were represented by Item_field objects. If the outer select employs a temporary table all such fields should be replaced with fields from that temporary table in order to point to the actual data. This replacement wasn't done and that resulted in a wrong subquery result and wrong result of the whole query. Now any outer field is represented by two objects - Item_field placed in the outer select and Item_ref in the subquery. Item_field object is processed as a normal field and takes place in the ref_pointer_array, if there is a temporary table it is copied there, so on. Thus the Item_ref is always references the correct field. Original field is substituted with the reference in the Item_field::fix_outer_field() function. New function called fix_inner_refs() is added to fix fields referenced from inner selects and references (Item_ref objects) to these fields. Item_ref class is updated to behave more like Item_field when used to represent an outer reference.
[20 Feb 2007 14:22]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/20183 ChangeSet@1.2408, 2007-02-20 16:12:14+03:00, evgen@moonbone.local +11 -0 Bug#23800: Outer fields in correlated subqueries is used in a temporary table created for sorting. Any outer reference in a subquery was represented by an Item_field object. If the outer select employs a temporary table all such fields should be replaced with fields from that temporary table in order to point to the actual data. This replacement wasn't done and that resulted in a wrong subquery evaluation and a wrong result of the whole query. Now any outer field is represented by two objects - Item_field placed in the outer select and Item_outer_ref in the subquery. Item_field object is processed as a normal field and the reference to it is saved in the ref_pointer_array. Thus the Item_outer_ref is always references the correct field. The original field is substituted for a reference in the Item_field::fix_outer_field() function. New function called fix_inner_refs() is added to fix fields referenced from inner selects and to fix references (Item_ref objects) to these fields. The new Item_outer_ref class is a descendant of the Item_direct_ref class. It additionally stores a reference to the original field and designed to behave more like a field.
[21 Feb 2007 20:01]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/20314 ChangeSet@1.2408, 2007-02-21 23:00:32+03:00, evgen@moonbone.local +11 -0 Bug#23800: Outer fields in correlated subqueries is used in a temporary table created for sorting. Any outer reference in a subquery was represented by an Item_field object. If the outer select employs a temporary table all such fields should be replaced with fields from that temporary table in order to point to the actual data. This replacement wasn't done and that resulted in a wrong subquery evaluation and a wrong result of the whole query. Now any outer field is represented by two objects - Item_field placed in the outer select and Item_outer_ref in the subquery. Item_field object is processed as a normal field and the reference to it is saved in the ref_pointer_array. Thus the Item_outer_ref is always references the correct field. The original field is substituted for a reference in the Item_field::fix_outer_field() function. New function called fix_inner_refs() is added to fix fields referenced from inner selects and to fix references (Item_ref objects) to these fields. The new Item_outer_ref class is a descendant of the Item_direct_ref class. It additionally stores a reference to the original field and designed to behave more like a field.
[23 Feb 2007 18:21]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/20485 ChangeSet@1.2418, 2007-02-23 20:44:31+03:00, evgen@moonbone.local +4 -0 item.h: Post fix for bug#23800. Added the subselect_items_processor() method to the Item class. item_subselect.h, item_subselect.cc: Post fix for bug#23800. Added function Item_subselect::subselect_items_processor(). sql_lex.cc: Post fix for bug#23800. A subselect might add fields it refers to to the outer selects' ref_pointer_array. Not taking this into account in the st_select_lex::setup_ref_array() function may lead to a memory corruption and to a crash.
[28 Feb 2007 17:42]
Sergei Glukhov
Fixed in 5.0.38, 5.1.17-beta
[6 Mar 2007 19:30]
Paul DuBois
Noted in 5.0.38, 5.1.17 changelogs. Queries that used a temporary table for the outer query when evaluating a correlated subquery could return incorrect results.

Description: When running a query with a correlated sub query the results are fine untill you operate upon them with count(parent.table.col): select ((select sum(tab1.weight) from tab1 where tab1.linkid = tab0.id) * count(tab0.id)) as col0 from tab0 group by tab0.id; From what I can see, when the sub query is operated apon with a value from the parent table only the last results from the group by are used. I have recreated this in 5.0.26 and 5.0.27, 5.0.24 is fine, I have not checked 5.0.25. I have provided a better example in the "How to repeat" section. How to repeat: create table students ( id int primary key auto_increment, name varchar(32) ); create table slips ( id int primary key auto_increment, studentid int, pevent int ); create table events ( id int primary key auto_increment, weight int ); insert into students(name) values('Andrew'), ('Chris'), ('Clare'); insert into events(weight) values(1),(3),(6),(9); insert into slips(studentid, pevent) values(1, 1), (1,2), (1,3), (1,4); insert into slips(studentid, pevent) values(2, 1), (2,2), (2,3), (2,1); insert into slips(studentid, pevent) values(3, 1), (3,1), (3,1), (3,4); select (select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) as BI from students as a, slips as d where a.id = d.studentid group by a.id; select ((select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) * count(d.id)) as BI from students as a, slips as d where a.id = d.studentid group by a.id; Version 5.0.24 mysql> select (select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) as BI from students as a, slips as d where -> a.id = d.studentid group by a.id; +------+ | BI | +------+ | 19 | | 11 | | 12 | +------+ 3 rows in set (0.00 sec) mysql> mysql> select ((select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) * count(d.id)) as BI from students as a, slips as d where -> a.id = d.studentid group by a.id; +------+ | BI | +------+ | 76 | | 44 | | 48 | +------+ 3 rows in set (0.00 sec) Version 5.0.26-27 mysql> select (select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) as BI from students as a, slips as d where -> a.id = d.studentid group by a.id; +------+ | BI | +------+ | 19 | | 11 | | 12 | +------+ 3 rows in set (0.00 sec) mysql> mysql> select ((select sum(c.weight) from slips as b, events as c where b.pevent = c.id and b.studentid = a.id) * count(d.id)) as BI from students as a, slips as d where -> a.id = d.studentid group by a.id; +------+ | BI | +------+ | 48 | | 48 | | 48 | +------+ 3 rows in set (0.00 sec)