From 546a166b4e1a52d63694caa38bc737e18fd8e98b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Mar 2011 23:23:44 +0200 Subject: [PATCH] Fix LP BUG#719198 Analysis: The assert failed because the execution code for partial matching is designed with the assumption that NULLs on the left side are detected as early as possible, and a NULL result is returned before any lookups are performed at all. However, in the case of an Item_cache object on the left side, null was not detected properly, because detection was done via Item::is_null(), which is not implemented at all for Item_cache, and resolved to the default Item::is_null() which always returns FALSE. Solution: Use the property Item::null_value instead of is_null(), which is properly updated for Item_cache objects as well. --- mysql-test/r/subselect_mat.result | 38 +++++++++++++++++++++++++++++++ mysql-test/t/subselect_mat.test | 28 +++++++++++++++++++++++ sql/item.h | 7 ++++++ sql/item_subselect.cc | 2 +- 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index e08872a648b..b7d2b5bb270 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -1371,3 +1371,41 @@ SELECT pk FROM t1 WHERE (b,c,d) IN (SELECT b,c,d FROM t2 WHERE pk > 0); pk 2 DROP TABLE t1, t2; +# +# LPBUG#719198 Ordered_key::cmp_key_with_search_key(rownum_t): Assertion `!compare_pred[i]->null_value' +# failed with subquery on both sides of NOT IN and materialization +# +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int, f3b int); +set session optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off'; +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t3 system NULL NULL NULL NULL 0 const row not found +SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); +f2 +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t3 system NULL NULL NULL NULL 0 const row not found +SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); +f2 +insert into t3 values (1,1),(2,2); +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +3 SUBQUERY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t2 WHERE (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1); +f2 +3 +4 +drop table t1, t2, t3; diff --git a/mysql-test/t/subselect_mat.test b/mysql-test/t/subselect_mat.test index e564ed36040..2664d2a31b4 100644 --- a/mysql-test/t/subselect_mat.test +++ b/mysql-test/t/subselect_mat.test @@ -1011,3 +1011,31 @@ SELECT pk FROM t1 WHERE (a) IN (SELECT a FROM t2 WHERE pk > 0); SELECT pk FROM t1 WHERE (b,c,d) IN (SELECT b,c,d FROM t2 WHERE pk > 0); DROP TABLE t1, t2; +--echo # +--echo # LPBUG#719198 Ordered_key::cmp_key_with_search_key(rownum_t): Assertion `!compare_pred[i]->null_value' +--echo # failed with subquery on both sides of NOT IN and materialization +--echo # + +CREATE TABLE t1 (f1a int, f1b int) ; +INSERT IGNORE INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 ( f2 int); +INSERT IGNORE INTO t2 VALUES (3),(4); +CREATE TABLE t3 (f3a int, f3b int); + +set session optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off'; + +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); +SELECT * FROM t2 WHERE (SELECT f3a FROM t3) NOT IN (SELECT f1a FROM t1); + +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); +SELECT * FROM t2 WHERE (SELECT f3a, f3b FROM t3) NOT IN (SELECT f1a, f1b FROM t1); + +insert into t3 values (1,1),(2,2); + +EXPLAIN +SELECT * FROM t2 WHERE (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1); +SELECT * FROM t2 WHERE (SELECT f3a FROM t3 where f3a > 3) NOT IN (SELECT f1a FROM t1); + +drop table t1, t2, t3; diff --git a/sql/item.h b/sql/item.h index 7c4b3c6e819..2340af9fdc6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3342,6 +3342,13 @@ private: }; +/** + @todo + Implement the is_null() method for this class. Currently calling is_null() + on any Item_cache object resolves to Item::is_null(), which reutns FALSE + for any value. +*/ + class Item_cache: public Item_basic_constant { protected: diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e89f8032e4f..8d10b80d171 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -5069,7 +5069,7 @@ bool subselect_rowid_merge_engine::partial_match() for (uint i= test(non_null_key); i < keys_count; i++) { DBUG_ASSERT(merge_keys[i]->get_column_count() == 1); - if (merge_keys[i]->get_search_key(0)->is_null()) + if (merge_keys[i]->get_search_key(0)->null_value) { ++count_nulls_in_search_key; bitmap_set_bit(&matching_outer_cols, merge_keys[i]->get_keyid());