Commit 990584d7 authored by unknown's avatar unknown

Fixed bug lp:809245

In addition to the bug fix explained below, the patch performs
few renames, and adds some comments to avoid similar problems.

Analysis:
The failed assert was due to a bug in MWL#68, where it was
incorrectly assumed that the size of the bitmap
subselect_rowid_merge_engine::null_only_columns should be
the same as the size of the array of Ordered_keys.

The bitmap null_only_columns contains bits to mark columns
that contain only NULLs. Therefore the indexes of the bits
to be set in null_only_columns are different from the indexes
of the Ordered_keys. If there is a NULL-only column that appears
in a table after the last partial match column with Ordered_key,
this NULL-only column would require setting a bit with index
bigger than the size of the bitmap null_only_columns.

Accessing such a bit caused the failed assert.

Solution:
Upon analysis, it turns out that null_only_columns is not needed
at all, because we are looking for partial matches, and having
such columns guarantees that there is a partial match for any
corresponding outer value.

Therefore the patch removes
  subselect_rowid_merge_engine::null_only_columns.
parent d4306393
set @save_optimizer_switch=@@optimizer_switch;
drop table if exists t1, t2; drop table if exists t1, t2;
# #
# LP BUG#608744 # LP BUG#608744
# #
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off"; set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off";
create table t1 (a1 char(1), a2 char(1)); create table t1 (a1 char(1), a2 char(1));
insert into t1 values (NULL, 'b'); insert into t1 values (NULL, 'b');
...@@ -11,7 +11,6 @@ insert into t2 values ('a','b'), ('c', 'd'); ...@@ -11,7 +11,6 @@ insert into t2 values ('a','b'), ('c', 'd');
select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2); select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2);
a1 a2 a1 a2
drop table t1,t2; drop table t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
# #
# LP BUG#601156 # LP BUG#601156
# #
...@@ -21,7 +20,6 @@ INSERT INTO t1 VALUES (4,NULL); ...@@ -21,7 +20,6 @@ INSERT INTO t1 VALUES (4,NULL);
CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL); CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL);
INSERT INTO t2 VALUES (6,NULL); INSERT INTO t2 VALUES (6,NULL);
INSERT INTO t2 VALUES (NULL,0); INSERT INTO t2 VALUES (NULL,0);
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on'; set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on';
EXPLAIN EXTENDED EXPLAIN EXTENDED
SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1; SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1;
...@@ -31,11 +29,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra ...@@ -31,11 +29,9 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings: Warnings:
Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b2` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `<subquery3>`.`b2`))))))) Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where (not(<in_optimizer>(`test`.`t1`.`a1`,`test`.`t1`.`a1` in ( <materialize> (select `test`.`t2`.`b2` from `test`.`t2` ), <primary_index_lookup>(`test`.`t1`.`a1` in <temporary table> on distinct_key where ((`test`.`t1`.`a1` = `<subquery3>`.`b2`)))))))
DROP TABLE t1, t2; DROP TABLE t1, t2;
set @@optimizer_switch=@save_optimizer_switch;
# #
# LP BUG#613009 Crash in Ordered_key::get_field_idx # LP BUG#613009 Crash in Ordered_key::get_field_idx
# #
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off'; set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off';
create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL); create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL);
insert into t1 values (NULL, 'a21'), (NULL, 'a22'); insert into t1 values (NULL, 'a21'), (NULL, 'a22');
...@@ -46,7 +42,6 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -46,7 +42,6 @@ id select_type table type possible_keys key key_len ref rows Extra
select * from t1 where (a1, a2) not in (select a1, a2 from t1); select * from t1 where (a1, a2) not in (select a1, a2 from t1);
a1 a2 a1 a2
drop table t1; drop table t1;
set @@optimizer_switch=@save_optimizer_switch;
# #
# LP BUG#680058 void Ordered_key::add_key(rownum_t): # LP BUG#680058 void Ordered_key::add_key(rownum_t):
# Assertion `key_buff_elements && cur_key_idx < key_buff_elements' failed # Assertion `key_buff_elements && cur_key_idx < key_buff_elements' failed
...@@ -55,10 +50,53 @@ create table t1 (f1 char(1), f2 char(1)); ...@@ -55,10 +50,53 @@ create table t1 (f1 char(1), f2 char(1));
insert into t1 values ('t', '0'), ('0', 't'); insert into t1 values ('t', '0'), ('0', 't');
create table t2 (f3 char(1), f4 char(1)); create table t2 (f3 char(1), f4 char(1));
insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y'); insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y');
set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
SET @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
select * from t1 where (f1, f2) not in (select * from t2); select * from t1 where (f1, f2) not in (select * from t2);
f1 f2 f1 f2
0 t 0 t
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2; drop table t1, t2;
#
# LP BUG#809245 Second assertion `bit < (map)->n_bits' with partial_match_merge
#
CREATE TABLE t1 (d varchar(32)) ;
INSERT INTO t1 VALUES ('r');
CREATE TABLE t2 ( a int, c varchar(32)) ;
INSERT INTO t2 VALUES (5,'r');
CREATE TABLE t3 ( a int NOT NULL , d varchar(32)) ;
INSERT INTO t3 VALUES (10,'g');
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
EXPLAIN SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY t3 system NULL NULL NULL NULL 1
2 SUBQUERY t2 system NULL NULL NULL NULL 1
SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
d
r
set @@optimizer_switch='materialization=off,in_to_exists=on';
EXPLAIN SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY t3 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY t2 system NULL NULL NULL NULL 1
SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
d
r
drop table t1, t2, t3;
set @@optimizer_switch=@save_optimizer_switch;
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# MWL#68: Subquery optimization: Efficient NOT IN execution with NULLs # MWL#68: Subquery optimization: Efficient NOT IN execution with NULLs
# #
set @save_optimizer_switch=@@optimizer_switch;
--disable_warnings --disable_warnings
drop table if exists t1, t2; drop table if exists t1, t2;
--enable_warnings --enable_warnings
...@@ -10,7 +12,6 @@ drop table if exists t1, t2; ...@@ -10,7 +12,6 @@ drop table if exists t1, t2;
--echo # --echo #
--echo # LP BUG#608744 --echo # LP BUG#608744
--echo # --echo #
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off"; set @@optimizer_switch="materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off";
create table t1 (a1 char(1), a2 char(1)); create table t1 (a1 char(1), a2 char(1));
insert into t1 values (NULL, 'b'); insert into t1 values (NULL, 'b');
...@@ -18,7 +19,6 @@ create table t2 (b1 char(1), b2 char(2)); ...@@ -18,7 +19,6 @@ create table t2 (b1 char(1), b2 char(2));
insert into t2 values ('a','b'), ('c', 'd'); insert into t2 values ('a','b'), ('c', 'd');
select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2); select * from t1 where (a1, a2) NOT IN (select b1, b2 from t2);
drop table t1,t2; drop table t1,t2;
set @@optimizer_switch=@save_optimizer_switch;
--echo # --echo #
...@@ -32,20 +32,17 @@ CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL); ...@@ -32,20 +32,17 @@ CREATE TABLE t2 (b1 int DEFAULT NULL, b2 int DEFAULT NULL);
INSERT INTO t2 VALUES (6,NULL); INSERT INTO t2 VALUES (6,NULL);
INSERT INTO t2 VALUES (NULL,0); INSERT INTO t2 VALUES (NULL,0);
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on'; set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=on';
EXPLAIN EXTENDED EXPLAIN EXTENDED
SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1; SELECT * FROM (SELECT * FROM t1 WHERE a1 NOT IN (SELECT b2 FROM t2)) table1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
set @@optimizer_switch=@save_optimizer_switch;
--echo # --echo #
--echo # LP BUG#613009 Crash in Ordered_key::get_field_idx --echo # LP BUG#613009 Crash in Ordered_key::get_field_idx
--echo # --echo #
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off'; set @@optimizer_switch='materialization=on,semijoin=off,partial_match_rowid_merge=on,partial_match_table_scan=off';
create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL); create table t1 (a1 char(3) DEFAULT NULL, a2 char(3) DEFAULT NULL);
...@@ -53,7 +50,6 @@ insert into t1 values (NULL, 'a21'), (NULL, 'a22'); ...@@ -53,7 +50,6 @@ insert into t1 values (NULL, 'a21'), (NULL, 'a22');
explain select * from t1 where (a1, a2) not in (select a1, a2 from t1); explain select * from t1 where (a1, a2) not in (select a1, a2 from t1);
select * from t1 where (a1, a2) not in (select a1, a2 from t1); select * from t1 where (a1, a2) not in (select a1, a2 from t1);
drop table t1; drop table t1;
set @@optimizer_switch=@save_optimizer_switch;
--echo # --echo #
--echo # LP BUG#680058 void Ordered_key::add_key(rownum_t): --echo # LP BUG#680058 void Ordered_key::add_key(rownum_t):
...@@ -65,8 +61,52 @@ insert into t1 values ('t', '0'), ('0', 't'); ...@@ -65,8 +61,52 @@ insert into t1 values ('t', '0'), ('0', 't');
create table t2 (f3 char(1), f4 char(1)); create table t2 (f3 char(1), f4 char(1));
insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y'); insert into t2 values ('t', NULL), ('t', NULL), ('d', 'y');
set @save_optimizer_switch=@@optimizer_switch; set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
SET @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,semijoin=off';
select * from t1 where (f1, f2) not in (select * from t2); select * from t1 where (f1, f2) not in (select * from t2);
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2; drop table t1, t2;
--echo #
--echo # LP BUG#809245 Second assertion `bit < (map)->n_bits' with partial_match_merge
--echo #
CREATE TABLE t1 (d varchar(32)) ;
INSERT INTO t1 VALUES ('r');
CREATE TABLE t2 ( a int, c varchar(32)) ;
INSERT INTO t2 VALUES (5,'r');
CREATE TABLE t3 ( a int NOT NULL , d varchar(32)) ;
INSERT INTO t3 VALUES (10,'g');
set @@optimizer_switch='materialization=on,partial_match_rowid_merge=on,partial_match_table_scan=off,in_to_exists=off';
EXPLAIN SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
set @@optimizer_switch='materialization=off,in_to_exists=on';
EXPLAIN SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
SELECT *
FROM t1
WHERE (t1.d , t1.d) NOT IN (
SELECT t3.d , t2.c
FROM t3 LEFT JOIN t2 ON t3.a = t2.a);
drop table t1, t2, t3;
set @@optimizer_switch=@save_optimizer_switch;
...@@ -3864,8 +3864,7 @@ subselect_hash_sj_engine::get_strategy_using_data() ...@@ -3864,8 +3864,7 @@ subselect_hash_sj_engine::get_strategy_using_data()
bitmap_set_bit(&non_null_key_parts, i); bitmap_set_bit(&non_null_key_parts, i);
--count_partial_match_columns; --count_partial_match_columns;
} }
if (result_sink->get_null_count_of_col(i) == if (result_sink->get_null_count_of_col(i) == tmp_table->file->stats.records)
tmp_table->file->stats.records)
++count_null_only_columns; ++count_null_only_columns;
} }
...@@ -5172,7 +5171,6 @@ void subselect_partial_match_engine::print(String *str, ...@@ -5172,7 +5171,6 @@ void subselect_partial_match_engine::print(String *str,
/* /*
@param non_null_key_parts @param non_null_key_parts
@param partial_match_key_parts A union of all single-column NULL key parts. @param partial_match_key_parts A union of all single-column NULL key parts.
@param count_partial_match_columns Number of NULL keyparts (set bits above).
@retval FALSE the engine was initialized successfully @retval FALSE the engine was initialized successfully
@retval TRUE there was some (memory allocation) error during initialization, @retval TRUE there was some (memory allocation) error during initialization,
...@@ -5189,24 +5187,24 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5189,24 +5187,24 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
rownum_t cur_rownum= 0; rownum_t cur_rownum= 0;
select_materialize_with_stats *result_sink= select_materialize_with_stats *result_sink=
(select_materialize_with_stats *) result; (select_materialize_with_stats *) result;
uint cur_keyid= 0; uint cur_keyid;
Item_in_subselect *item_in= (Item_in_subselect*) item; Item_in_subselect *item_in= (Item_in_subselect*) item;
int error; int error;
if (keys_count == 0) if (merge_keys_count == 0)
{ {
/* There is nothing to initialize, we will only do regular lookups. */ /* There is nothing to initialize, we will only do regular lookups. */
return FALSE; return FALSE;
} }
DBUG_ASSERT(!covering_null_row_width || (covering_null_row_width && DBUG_ASSERT(!covering_null_row_width || (covering_null_row_width &&
keys_count == 1 && merge_keys_count == 1 &&
non_null_key_parts)); non_null_key_parts));
/* /*
Allocate buffers to hold the merged keys and the mapping between rowids and Allocate buffers to hold the merged keys and the mapping between rowids and
row numbers. row numbers.
*/ */
if (!(merge_keys= (Ordered_key**) thd->alloc(keys_count * if (!(merge_keys= (Ordered_key**) thd->alloc(merge_keys_count *
sizeof(Ordered_key*))) || sizeof(Ordered_key*))) ||
!(row_num_to_rowid= (uchar*) my_malloc((size_t)(row_count * rowid_length), !(row_num_to_rowid= (uchar*) my_malloc((size_t)(row_count * rowid_length),
MYF(MY_WME)))) MYF(MY_WME))))
...@@ -5215,14 +5213,16 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5215,14 +5213,16 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
/* Create the only non-NULL key if there is any. */ /* Create the only non-NULL key if there is any. */
if (non_null_key_parts) if (non_null_key_parts)
{ {
non_null_key= new Ordered_key(cur_keyid, tmp_table, item_in->left_expr, non_null_key= new Ordered_key(0, tmp_table, item_in->left_expr,
0, 0, 0, row_num_to_rowid); 0, 0, 0, row_num_to_rowid);
if (non_null_key->init(non_null_key_parts)) if (non_null_key->init(non_null_key_parts))
return TRUE; return TRUE;
merge_keys[cur_keyid]= non_null_key; merge_keys[0]= non_null_key;
merge_keys[cur_keyid]->first(); merge_keys[0]->first();
++cur_keyid; cur_keyid= 1;
} }
else
cur_keyid= 0;
/* /*
If there is a covering NULL row, the only key that is needed is the If there is a covering NULL row, the only key that is needed is the
...@@ -5231,9 +5231,8 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5231,9 +5231,8 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
*/ */
if (!covering_null_row_width) if (!covering_null_row_width)
{ {
if (bitmap_init_memroot(&matching_keys, keys_count, thd->mem_root) || if (bitmap_init_memroot(&matching_keys, merge_keys_count, thd->mem_root) ||
bitmap_init_memroot(&matching_outer_cols, keys_count, thd->mem_root) || bitmap_init_memroot(&matching_outer_cols, merge_keys_count, thd->mem_root))
bitmap_init_memroot(&null_only_columns, keys_count, thd->mem_root))
return TRUE; return TRUE;
/* /*
...@@ -5242,31 +5241,25 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5242,31 +5241,25 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
*/ */
for (uint i= 0; i < partial_match_key_parts->n_bits; i++) for (uint i= 0; i < partial_match_key_parts->n_bits; i++)
{ {
if (!bitmap_is_set(partial_match_key_parts, i)) /* Skip columns that have no NULLs, or contain only NULLs. */
if (!bitmap_is_set(partial_match_key_parts, i) ||
result_sink->get_null_count_of_col(i) == row_count)
continue; continue;
if (result_sink->get_null_count_of_col(i) == row_count) merge_keys[cur_keyid]= new Ordered_key(
{
bitmap_set_bit(&null_only_columns, cur_keyid);
continue;
}
else
{
merge_keys[cur_keyid]= new Ordered_key(
cur_keyid, tmp_table, cur_keyid, tmp_table,
item_in->left_expr->element_index(i), item_in->left_expr->element_index(i),
result_sink->get_null_count_of_col(i), result_sink->get_null_count_of_col(i),
result_sink->get_min_null_of_col(i), result_sink->get_min_null_of_col(i),
result_sink->get_max_null_of_col(i), result_sink->get_max_null_of_col(i),
row_num_to_rowid); row_num_to_rowid);
if (merge_keys[cur_keyid]->init(i)) if (merge_keys[cur_keyid]->init(i))
return TRUE; return TRUE;
merge_keys[cur_keyid]->first(); merge_keys[cur_keyid]->first();
}
++cur_keyid; ++cur_keyid;
} }
} }
DBUG_ASSERT(cur_keyid == keys_count); DBUG_ASSERT(cur_keyid == merge_keys_count);
/* Populate the indexes with data from the temporary table. */ /* Populate the indexes with data from the temporary table. */
if (tmp_table->file->ha_rnd_init_with_error(1)) if (tmp_table->file->ha_rnd_init_with_error(1))
...@@ -5307,7 +5300,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5307,7 +5300,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
non_null_key->add_key(cur_rownum); non_null_key->add_key(cur_rownum);
} }
for (uint i= (non_null_key ? 1 : 0); i < keys_count; i++) for (uint i= (non_null_key ? 1 : 0); i < merge_keys_count; i++)
{ {
/* /*
Check if the first and only indexed column contains NULL in the curent Check if the first and only indexed column contains NULL in the curent
...@@ -5324,14 +5317,14 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5324,14 +5317,14 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
tmp_table->file->ha_rnd_end(); tmp_table->file->ha_rnd_end();
/* Sort all the keys by their NULL selectivity. */ /* Sort all the keys by their NULL selectivity. */
my_qsort(merge_keys, keys_count, sizeof(Ordered_key*), my_qsort(merge_keys, merge_keys_count, sizeof(Ordered_key*),
(qsort_cmp) cmp_keys_by_null_selectivity); (qsort_cmp) cmp_keys_by_null_selectivity);
/* Sort the keys in each of the indexes. */ /* Sort the keys in each of the indexes. */
for (uint i= 0; i < keys_count; i++) for (uint i= 0; i < merge_keys_count; i++)
merge_keys[i]->sort_keys(); merge_keys[i]->sort_keys();
if (init_queue(&pq, keys_count, 0, FALSE, if (init_queue(&pq, merge_keys_count, 0, FALSE,
subselect_rowid_merge_engine::cmp_keys_by_cur_rownum, NULL, subselect_rowid_merge_engine::cmp_keys_by_cur_rownum, NULL,
0, 0)) 0, 0))
return TRUE; return TRUE;
...@@ -5343,10 +5336,10 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, ...@@ -5343,10 +5336,10 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts,
subselect_rowid_merge_engine::~subselect_rowid_merge_engine() subselect_rowid_merge_engine::~subselect_rowid_merge_engine()
{ {
/* None of the resources below is allocated if there are no ordered keys. */ /* None of the resources below is allocated if there are no ordered keys. */
if (keys_count) if (merge_keys_count)
{ {
my_free((char*) row_num_to_rowid, MYF(0)); my_free((char*) row_num_to_rowid, MYF(0));
for (uint i= 0; i < keys_count; i++) for (uint i= 0; i < merge_keys_count; i++)
delete merge_keys[i]; delete merge_keys[i];
delete_queue(&pq); delete_queue(&pq);
if (tmp_table->file->inited == handler::RND) if (tmp_table->file->inited == handler::RND)
...@@ -5404,6 +5397,10 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg, ...@@ -5404,6 +5397,10 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg,
Check if certain table row contains a NULL in all columns for which there is Check if certain table row contains a NULL in all columns for which there is
no match in the corresponding value index. no match in the corresponding value index.
@note
There is no need to check the columns that contain only NULLs, because
those are guaranteed to match.
@retval TRUE if a NULL row exists @retval TRUE if a NULL row exists
@retval FALSE otherwise @retval FALSE otherwise
*/ */
...@@ -5411,16 +5408,14 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg, ...@@ -5411,16 +5408,14 @@ subselect_rowid_merge_engine::cmp_keys_by_cur_rownum(void *arg,
bool subselect_rowid_merge_engine::test_null_row(rownum_t row_num) bool subselect_rowid_merge_engine::test_null_row(rownum_t row_num)
{ {
Ordered_key *cur_key; Ordered_key *cur_key;
uint cur_id; for (uint i = 0; i < merge_keys_count; i++)
for (uint i = 0; i < keys_count; i++)
{ {
cur_key= merge_keys[i]; cur_key= merge_keys[i];
cur_id= cur_key->get_keyid(); if (bitmap_is_set(&matching_keys, cur_key->get_keyid()))
if (bitmap_is_set(&matching_keys, cur_id))
{ {
/* /*
The key 'i' (with id 'cur_keyid') already matches a value in row 'row_num', The key 'i' (with id 'cur_keyid') already matches a value in row
thus we skip it as it can't possibly match a NULL. 'row_num', thus we skip it as it can't possibly match a NULL.
*/ */
continue; continue;
} }
...@@ -5481,7 +5476,7 @@ bool subselect_rowid_merge_engine::partial_match() ...@@ -5481,7 +5476,7 @@ bool subselect_rowid_merge_engine::partial_match()
Do not add the non_null_key, since it was already processed above. Do not add the non_null_key, since it was already processed above.
*/ */
bitmap_clear_all(&matching_outer_cols); bitmap_clear_all(&matching_outer_cols);
for (uint i= test(non_null_key); i < keys_count; i++) for (uint i= test(non_null_key); i < merge_keys_count; i++)
{ {
DBUG_ASSERT(merge_keys[i]->get_column_count() == 1); DBUG_ASSERT(merge_keys[i]->get_column_count() == 1);
if (merge_keys[i]->get_search_key(0)->null_value) if (merge_keys[i]->get_search_key(0)->null_value)
...@@ -5519,7 +5514,6 @@ bool subselect_rowid_merge_engine::partial_match() ...@@ -5519,7 +5514,6 @@ bool subselect_rowid_merge_engine::partial_match()
min_key= (Ordered_key*) queue_remove_top(&pq); min_key= (Ordered_key*) queue_remove_top(&pq);
min_row_num= min_key->current(); min_row_num= min_key->current();
bitmap_copy(&matching_keys, &null_only_columns);
bitmap_set_bit(&matching_keys, min_key->get_keyid()); bitmap_set_bit(&matching_keys, min_key->get_keyid());
bitmap_union(&matching_keys, &matching_outer_cols); bitmap_union(&matching_keys, &matching_outer_cols);
if (min_key->next_same()) if (min_key->next_same())
...@@ -5555,7 +5549,6 @@ bool subselect_rowid_merge_engine::partial_match() ...@@ -5555,7 +5549,6 @@ bool subselect_rowid_merge_engine::partial_match()
{ {
min_key= cur_key; min_key= cur_key;
min_row_num= cur_row_num; min_row_num= cur_row_num;
bitmap_copy(&matching_keys, &null_only_columns);
bitmap_set_bit(&matching_keys, min_key->get_keyid()); bitmap_set_bit(&matching_keys, min_key->get_keyid());
bitmap_union(&matching_keys, &matching_outer_cols); bitmap_union(&matching_keys, &matching_outer_cols);
} }
......
...@@ -1191,11 +1191,6 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine ...@@ -1191,11 +1191,6 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine
outer reference. outer reference.
*/ */
MY_BITMAP matching_outer_cols; MY_BITMAP matching_outer_cols;
/*
Columns that consist of only NULLs. Such columns match any value.
Computed once per query execution.
*/
MY_BITMAP null_only_columns;
/* /*
Indexes of row numbers, sorted by <column_value, row_number>. If an Indexes of row numbers, sorted by <column_value, row_number>. If an
index may contain NULLs, the NULLs are stored efficiently in a bitmap. index may contain NULLs, the NULLs are stored efficiently in a bitmap.
...@@ -1205,13 +1200,13 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine ...@@ -1205,13 +1200,13 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine
non-NULL columns, it is contained in keys[0]. non-NULL columns, it is contained in keys[0].
*/ */
Ordered_key **merge_keys; Ordered_key **merge_keys;
/* The number of elements in keys. */ /* The number of elements in merge_keys. */
uint keys_count; uint merge_keys_count;
/* /*
An index on all non-NULL columns of 'tmp_table'. The index has the An index on all non-NULL columns of 'tmp_table'. The index has the
logical form: <[v_i1 | ... | v_ik], rownum>. It allows to find the row logical form: <[v_i1 | ... | v_ik], rownum>. It allows to find the row
number where the columns c_i1,...,c1_k contain the values v_i1,...,v_ik. number where the columns c_i1,...,c1_k contain the values v_i1,...,v_ik.
If such an index exists, it is always the first element of 'keys'. If such an index exists, it is always the first element of 'merge_keys'.
*/ */
Ordered_key *non_null_key; Ordered_key *non_null_key;
/* /*
...@@ -1236,7 +1231,7 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine ...@@ -1236,7 +1231,7 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine
public: public:
subselect_rowid_merge_engine(THD *thd_arg, subselect_rowid_merge_engine(THD *thd_arg,
subselect_uniquesubquery_engine *engine_arg, subselect_uniquesubquery_engine *engine_arg,
TABLE *tmp_table_arg, uint keys_count_arg, TABLE *tmp_table_arg, uint merge_keys_count_arg,
uint covering_null_row_width_arg, uint covering_null_row_width_arg,
Item_subselect *item_arg, Item_subselect *item_arg,
select_result_interceptor *result_arg, select_result_interceptor *result_arg,
...@@ -1244,7 +1239,7 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine ...@@ -1244,7 +1239,7 @@ class subselect_rowid_merge_engine: public subselect_partial_match_engine
:subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg, :subselect_partial_match_engine(thd_arg, engine_arg, tmp_table_arg,
item_arg, result_arg, equi_join_conds_arg, item_arg, result_arg, equi_join_conds_arg,
covering_null_row_width_arg), covering_null_row_width_arg),
keys_count(keys_count_arg), non_null_key(NULL) merge_keys_count(merge_keys_count_arg), non_null_key(NULL)
{} {}
~subselect_rowid_merge_engine(); ~subselect_rowid_merge_engine();
bool init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts); bool init(MY_BITMAP *non_null_key_parts, MY_BITMAP *partial_match_key_parts);
......
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