MDEV-5056: Wrong result (extra rows) with materialization+semijoin, IN subqueries

Apply fix suggested by Igor:
- When eliminate_item_equal() generates pair-wise equalities from a 
  multi-equality,  do generate a "bridge" equality between the first 
  field inside SJM nest and the field that's first in the overall multi-equality.
This commit is contained in:
Sergey Petrunya 2013-11-13 07:40:46 +04:00
commit 229aa1d4bf
4 changed files with 72 additions and 2 deletions

View file

@ -2038,6 +2038,27 @@ SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
pk a b
DROP TABLE t1;
# End of 5.3 tests
#
# MDEV-5056: Wrong result (extra rows) with materialization+semijoin, IN subqueries
#
set @tmp_mdev5056=@@join_cache_level;
SET join_cache_level = 2;
CREATE TABLE t1 ( c1 VARCHAR(2), c2 VARCHAR(2), INDEX(c1) ) ENGINE=MyISAM;
INSERT INTO t1 VALUES
('JP','OM'),('VA','JP'),('CA','ML'),('ML','EG'),('DK','CA'),
('DK','QA'),('YE','PL'),('TR','ZW'),('DK','SK'),('SK','DK'),
('RO','ML'),('ML','BG'),('BG','ZW'),('ZW','GE'),('GE','JP'),
('PL','EG'),('QA','YE'),('WF','DK'),('DK','JP'),('EG','OM');
CREATE TABLE t2 ( c3 VARCHAR(2), c4 VARCHAR(2) ) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('CA','ML'),('IN','HU'),('HU','IN');
SELECT * FROM t1 AS alias1, t1 AS alias2
WHERE ( alias2.c2, alias1.c1 ) IN ( SELECT c4, c3 FROM t2 ) AND alias1.c1 IN ( SELECT c2 FROM t1 );
c1 c2 c1 c2
CA ML CA ML
CA ML RO ML
DROP TABLE t1,t2;
set join_cache_level=@tmp_mdev5056;
# End of 5.5 tests
set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on';

View file

@ -2078,3 +2078,24 @@ SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
pk a b
DROP TABLE t1;
# End of 5.3 tests
#
# MDEV-5056: Wrong result (extra rows) with materialization+semijoin, IN subqueries
#
set @tmp_mdev5056=@@join_cache_level;
SET join_cache_level = 2;
CREATE TABLE t1 ( c1 VARCHAR(2), c2 VARCHAR(2), INDEX(c1) ) ENGINE=MyISAM;
INSERT INTO t1 VALUES
('JP','OM'),('VA','JP'),('CA','ML'),('ML','EG'),('DK','CA'),
('DK','QA'),('YE','PL'),('TR','ZW'),('DK','SK'),('SK','DK'),
('RO','ML'),('ML','BG'),('BG','ZW'),('ZW','GE'),('GE','JP'),
('PL','EG'),('QA','YE'),('WF','DK'),('DK','JP'),('EG','OM');
CREATE TABLE t2 ( c3 VARCHAR(2), c4 VARCHAR(2) ) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('CA','ML'),('IN','HU'),('HU','IN');
SELECT * FROM t1 AS alias1, t1 AS alias2
WHERE ( alias2.c2, alias1.c1 ) IN ( SELECT c4, c3 FROM t2 ) AND alias1.c1 IN ( SELECT c2 FROM t1 );
c1 c2 c1 c2
CA ML CA ML
CA ML RO ML
DROP TABLE t1,t2;
set join_cache_level=@tmp_mdev5056;
# End of 5.5 tests

View file

@ -1726,3 +1726,29 @@ SELECT * FROM t1 WHERE 8 IN (SELECT MIN(pk) FROM t1) AND (pk = a OR pk = b);
DROP TABLE t1;
--echo # End of 5.3 tests
--echo #
--echo # MDEV-5056: Wrong result (extra rows) with materialization+semijoin, IN subqueries
--echo #
set @tmp_mdev5056=@@join_cache_level;
SET join_cache_level = 2;
CREATE TABLE t1 ( c1 VARCHAR(2), c2 VARCHAR(2), INDEX(c1) ) ENGINE=MyISAM;
INSERT INTO t1 VALUES
('JP','OM'),('VA','JP'),('CA','ML'),('ML','EG'),('DK','CA'),
('DK','QA'),('YE','PL'),('TR','ZW'),('DK','SK'),('SK','DK'),
('RO','ML'),('ML','BG'),('BG','ZW'),('ZW','GE'),('GE','JP'),
('PL','EG'),('QA','YE'),('WF','DK'),('DK','JP'),('EG','OM');
CREATE TABLE t2 ( c3 VARCHAR(2), c4 VARCHAR(2) ) ENGINE=MyISAM;
INSERT INTO t2 VALUES ('CA','ML'),('IN','HU'),('HU','IN');
SELECT * FROM t1 AS alias1, t1 AS alias2
WHERE ( alias2.c2, alias1.c1 ) IN ( SELECT c4, c3 FROM t2 ) AND alias1.c1 IN ( SELECT c2 FROM t1 );
DROP TABLE t1,t2;
set join_cache_level=@tmp_mdev5056;
--echo # End of 5.5 tests

View file

@ -12295,12 +12295,14 @@ Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
/*
If we're inside an SJM-nest (current_sjm!=NULL), and the multi-equality
doesn't include a constant, we should produce equality with the first
of the equals in this SJM.
of the equal items in this SJM (except for the first element inside the
SJM. For that, we produce the equality with the "head" item).
In other cases, get the "head" item, which is either first of the
equals on top level, or the constant.
*/
Item *head_item= (!item_const && current_sjm)? current_sjm_head: head;
Item *head_item= (!item_const && current_sjm &&
current_sjm_head != field_item) ? current_sjm_head: head;
Item *head_real_item= head_item->real_item();
if (head_real_item->type() == Item::FIELD_ITEM)
head_item= head_real_item;