Commit 7c7611d7 authored by Sergey Petrunya's avatar Sergey Petrunya

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.
parent e0500dbc
...@@ -727,4 +727,34 @@ SELECT a, MIN(c) FROM t1 WHERE b = 'x' AND c > 'x' GROUP BY a; ...@@ -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;
...@@ -227,4 +227,34 @@ SELECT a, MIN(c) FROM t1 WHERE b = 'x' AND c > 'x' GROUP BY a; ...@@ -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;
...@@ -9101,11 +9101,9 @@ uint check_join_cache_usage(JOIN_TAB *tab, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ||
......
...@@ -136,6 +136,7 @@ typedef struct st_table_ref ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment