BUG#887026: Wrong result with ICP, outer join, subquery in maria-5.3-icp

- Do not push index condition if we're using a triggered ref access.
This commit is contained in:
Sergey Petrunya 2011-11-07 23:30:03 +04:00
parent e0500dbc3a
commit 7c7611d728
4 changed files with 86 additions and 16 deletions

View File

@ -727,4 +727,34 @@ SELECT a, MIN(c) FROM t1 WHERE b = 'x' AND c > 'x' GROUP BY a;
a MIN(c) a MIN(c)
5 y 5 y
DROP TABLE t1; DROP TABLE t1;
#
# BUG#887026: Wrong result with ICP, outer join, subquery in maria-5.3-icp
#
CREATE TABLE t1 (c varchar(1));
INSERT INTO t1 VALUES ('c'), ('c');
CREATE TABLE t2 (c varchar(1), b int);
INSERT INTO t2 VALUES ('d', NULL),('d', NULL);
CREATE TABLE t3 (c varchar(1));
INSERT INTO t3 VALUES ('c');
INSERT INTO t3 VALUES ('c');
CREATE TABLE t4 ( b int, c varchar(1), KEY (b));
INSERT INTO t4 VALUES (7,'c');
INSERT INTO t4 VALUES (7,'c');
# Must be t1,t2,t3,t4, with t4 having Full-scan-on-NULL but not Using index condition
explain
SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b
WHERE
t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 2
2 DEPENDENT SUBQUERY t4 ref_or_null b b 5 func 2 Using where; Full scan on NULL key
SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b
WHERE
t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c);
c c b
c NULL NULL
c NULL NULL
DROP TABLE t1,t2,t3,t4;
set optimizer_switch=@myisam_icp_tmp; set optimizer_switch=@myisam_icp_tmp;

View File

@ -227,4 +227,34 @@ SELECT a, MIN(c) FROM t1 WHERE b = 'x' AND c > 'x' GROUP BY a;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # BUG#887026: Wrong result with ICP, outer join, subquery in maria-5.3-icp
--echo #
CREATE TABLE t1 (c varchar(1));
INSERT INTO t1 VALUES ('c'), ('c');
CREATE TABLE t2 (c varchar(1), b int);
INSERT INTO t2 VALUES ('d', NULL),('d', NULL);
CREATE TABLE t3 (c varchar(1));
INSERT INTO t3 VALUES ('c');
INSERT INTO t3 VALUES ('c');
CREATE TABLE t4 ( b int, c varchar(1), KEY (b));
INSERT INTO t4 VALUES (7,'c');
INSERT INTO t4 VALUES (7,'c');
--echo # Must be t1,t2,t3,t4, with t4 having Full-scan-on-NULL but not Using index condition
explain
SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b
WHERE
t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c);
SELECT * FROM t1 LEFT JOIN t2 ON t1.c=t2.b
WHERE
t2.b NOT IN (SELECT t4.b FROM t3 STRAIGHT_JOIN t4 WHERE t4.b <= 2 AND t4.c = t3.c);
DROP TABLE t1,t2,t3,t4;
set optimizer_switch=@myisam_icp_tmp; set optimizer_switch=@myisam_icp_tmp;

View File

@ -9101,11 +9101,9 @@ uint check_join_cache_usage(JOIN_TAB *tab,
case JT_EQ_REF: case JT_EQ_REF:
if (cache_level <=2 || (no_hashed_cache && no_bka_cache)) if (cache_level <=2 || (no_hashed_cache && no_bka_cache))
goto no_join_cache; goto no_join_cache;
for (uint i= 0; i < tab->ref.key_parts; i++) if (tab->ref.is_access_triggered())
{ goto no_join_cache;
if (tab->ref.cond_guards[i])
goto no_join_cache;
}
if (!tab->is_ref_for_hash_join()) if (!tab->is_ref_for_hash_join())
{ {
flags= HA_MRR_NO_NULL_ENDPOINTS | HA_MRR_SINGLE_POINT; flags= HA_MRR_NO_NULL_ENDPOINTS | HA_MRR_SINGLE_POINT;
@ -9396,9 +9394,9 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
table->key_read=1; table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD); table->file->extra(HA_EXTRA_KEYREAD);
} }
else if (!jcl || jcl > 4) else if ((!jcl || jcl > 4) && !tab->ref.is_access_triggered())
push_index_cond(tab, tab->ref.key); push_index_cond(tab, tab->ref.key);
break; break;
case JT_EQ_REF: case JT_EQ_REF:
tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.unlock_row= join_read_key_unlock_row;
/* fall through */ /* fall through */
@ -9408,7 +9406,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
table->key_read=1; table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD); table->file->extra(HA_EXTRA_KEYREAD);
} }
else if (!jcl || jcl > 4) else if ((!jcl || jcl > 4) && !tab->ref.is_access_triggered())
push_index_cond(tab, tab->ref.key); push_index_cond(tab, tab->ref.key);
break; break;
case JT_REF_OR_NULL: case JT_REF_OR_NULL:
@ -9423,7 +9421,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
if (table->covering_keys.is_set(tab->ref.key) && if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread) !table->no_keyread)
table->enable_keyread(); table->enable_keyread();
else if (!jcl || jcl > 4) else if ((!jcl || jcl > 4) && !tab->ref.is_access_triggered())
push_index_cond(tab, tab->ref.key); push_index_cond(tab, tab->ref.key);
break; break;
case JT_ALL: case JT_ALL:
@ -9780,6 +9778,22 @@ bool TABLE_REF::tmp_table_index_lookup_init(THD *thd,
} }
/*
Check if ref access uses "Full scan on NULL key" (i.e. it actually alternates
between ref access and full table scan)
*/
bool TABLE_REF::is_access_triggered()
{
for (uint i = 0; i < key_parts; i++)
{
if (cond_guards[i])
return TRUE;
}
return FALSE;
}
/** /**
Partially cleanup JOIN after it has executed: close index or rnd read Partially cleanup JOIN after it has executed: close index or rnd read
(table cursors), free quick selects. (table cursors), free quick selects.
@ -16656,13 +16670,8 @@ bool test_if_ref(Item *root_cond, Item_field *left_item,Item *right_item)
between ref access and full table scan), then no equality can be between ref access and full table scan), then no equality can be
guaranteed to be true. guaranteed to be true.
*/ */
for (uint i = 0; i < join_tab->ref.key_parts; i++) if (join_tab->ref.is_access_triggered())
{ return FALSE;
if (join_tab->ref.cond_guards[i])
{
return FALSE;
}
}
Item *ref_item=part_of_refkey(field->table,field); Item *ref_item=part_of_refkey(field->table,field);
if (ref_item && (ref_item->eq(right_item,1) || if (ref_item && (ref_item->eq(right_item,1) ||

View File

@ -136,6 +136,7 @@ typedef struct st_table_ref
bool tmp_table_index_lookup_init(THD *thd, KEY *tmp_key, Item_iterator &it, bool tmp_table_index_lookup_init(THD *thd, KEY *tmp_key, Item_iterator &it,
bool value, uint skip= 0); bool value, uint skip= 0);
bool is_access_triggered();
} TABLE_REF; } TABLE_REF;