diff --git a/mysql-test/r/hash_join_weedout.result b/mysql-test/r/hash_join_weedout.result new file mode 100644 index 00000000000..72d96baa9fa --- /dev/null +++ b/mysql-test/r/hash_join_weedout.result @@ -0,0 +1,41 @@ +CREATE TABLE a ( +pk INTEGER, +col_varchar VARCHAR(1), +col_varchar_key VARCHAR(1) +) +partition by hash(pk) partitions 11; +CREATE TABLE b ( +pk INTEGER NOT NULL AUTO_INCREMENT, +col_varchar VARCHAR(1), +col_varchar_key VARCHAR(1), +PRIMARY KEY (pk), +KEY varchar_key (col_varchar_key) +) +partition by key() partitions 11; +INSERT INTO a VALUES (1, 'N', '0'); +INSERT INTO b VALUES (1, '8', 'r'), (2, 'v', 'C'), (3, 'b', 'p'), (4, '7', 'W'); +SELECT 1 FROM (b AS table1 +INNER JOIN a AS table2 ON table2.pk = table1.pk OR table1.col_varchar < 'D') +WHERE (NOT EXISTS +(SELECT 1 FROM (b AS alias3 STRAIGHT_JOIN a AS alias4 +ON alias4.col_varchar = alias3.col_varchar_key) +WHERE alias3.pk >= table1.pk)); +1 +1 +1 +1 +INSERT INTO a VALUES (1, 'N', '0'); +SELECT 1 FROM (b AS table1 +INNER JOIN a AS table2 ON table2.pk = table1.pk OR table1.col_varchar < 'D') +WHERE (NOT EXISTS +(SELECT 1 FROM (b AS alias3 STRAIGHT_JOIN a AS alias4 +ON alias4.col_varchar = alias3.col_varchar_key) +WHERE alias3.pk >= table1.pk)); +1 +1 +1 +1 +1 +1 +1 +DROP TABLE a, b; diff --git a/mysql-test/t/hash_join_weedout.test b/mysql-test/t/hash_join_weedout.test new file mode 100644 index 00000000000..a638f866188 --- /dev/null +++ b/mysql-test/t/hash_join_weedout.test @@ -0,0 +1,36 @@ +CREATE TABLE a ( + pk INTEGER, + col_varchar VARCHAR(1), + col_varchar_key VARCHAR(1) +) +partition by hash(pk) partitions 11; + +CREATE TABLE b ( + pk INTEGER NOT NULL AUTO_INCREMENT, + col_varchar VARCHAR(1), + col_varchar_key VARCHAR(1), + PRIMARY KEY (pk), + KEY varchar_key (col_varchar_key) +) +partition by key() partitions 11; +INSERT INTO a VALUES (1, 'N', '0'); +INSERT INTO b VALUES (1, '8', 'r'), (2, 'v', 'C'), (3, 'b', 'p'), (4, '7', 'W'); + +SELECT 1 FROM (b AS table1 + INNER JOIN a AS table2 ON table2.pk = table1.pk OR table1.col_varchar < 'D') + WHERE (NOT EXISTS + (SELECT 1 FROM (b AS alias3 STRAIGHT_JOIN a AS alias4 + ON alias4.col_varchar = alias3.col_varchar_key) + WHERE alias3.pk >= table1.pk)); + +INSERT INTO a VALUES (1, 'N', '0'); + +SELECT 1 FROM (b AS table1 + INNER JOIN a AS table2 ON table2.pk = table1.pk OR table1.col_varchar < 'D') + WHERE (NOT EXISTS + (SELECT 1 FROM (b AS alias3 STRAIGHT_JOIN a AS alias4 + ON alias4.col_varchar = alias3.col_varchar_key) + WHERE alias3.pk >= table1.pk)); + +## clean up +DROP TABLE a, b; diff --git a/sql/hash_join_buffer.cc b/sql/hash_join_buffer.cc index de180a20108..53c21052d44 100644 --- a/sql/hash_join_buffer.cc +++ b/sql/hash_join_buffer.cc @@ -235,7 +235,7 @@ static bool ShouldCopyRowId(const hash_join_buffer::Table &tbl) { // It is not safe to copy the row ID if we have a NULL-complemented row; the // value is undefined, or the buffer location can even be nullptr. const TABLE *table = tbl.qep_tab->table(); - return tbl.rowid_status != NO_ROWID_NEEDED && !table->const_table && + return tbl.qep_tab->rowid_status != NO_ROWID_NEEDED && !table->const_table && !(table->is_nullable() && table->null_row); } diff --git a/sql/hash_join_iterator.cc b/sql/hash_join_iterator.cc index a3236507253..8498cd94308 100644 --- a/sql/hash_join_iterator.cc +++ b/sql/hash_join_iterator.cc @@ -101,12 +101,14 @@ HashJoinIterator::HashJoinIterator( if (it.qep_tab->rowid_status == NEED_TO_CALL_POSITION_FOR_ROWID) { it.qep_tab->rowid_status = ROWID_PROVIDED_BY_ITERATOR_READ_CALL; } + it.qep_tab->hj_iterator = this; } for (const hash_join_buffer::Table &it : m_probe_input_table.tables()) { if (it.qep_tab->rowid_status == NEED_TO_CALL_POSITION_FOR_ROWID) { it.qep_tab->rowid_status = ROWID_PROVIDED_BY_ITERATOR_READ_CALL; } + it.qep_tab->hj_iterator = this; } } @@ -290,7 +292,7 @@ static bool WriteRowToChunk( void RequestRowId(const Prealloced_array &tables) { for (const hash_join_buffer::Table &it : tables) { TABLE *table = it.qep_tab->table(); - if (it.rowid_status == NEED_TO_CALL_POSITION_FOR_ROWID && + if (it.qep_tab->rowid_status == ROWID_PROVIDED_BY_ITERATOR_READ_CALL && can_call_position(table)) { table->file->position(table->record[0]); } diff --git a/sql/sql_executor.h b/sql/sql_executor.h index 9ff9f1faa84..51c1f652583 100644 --- a/sql/sql_executor.h +++ b/sql/sql_executor.h @@ -50,6 +50,7 @@ class Field; class Field_longlong; class Filesort; class FollowTailIterator; +class HashJoinIterator; class Item; class Item_sum; class JOIN; @@ -795,6 +796,11 @@ class QEP_TAB : public QEP_shared_owner { */ FollowTailIterator *recursive_iterator = nullptr; + /** + If this table is belong to a hash join iterator, store hj_iterator here. + */ + HashJoinIterator *hj_iterator = nullptr; + QEP_TAB(const QEP_TAB &); // not defined QEP_TAB &operator=(const QEP_TAB &); // not defined }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 01d2fdfb92b..7de1e092b44 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1129,6 +1129,10 @@ SJ_TMP_TABLE *create_sj_tmp_table(THD *thd, JOIN *join, } qep_tab->table()->prepare_for_position(); qep_tab->rowid_status = NEED_TO_CALL_POSITION_FOR_ROWID; + // adjust the rowid_status, which will used in hash join + if (qep_tab->hj_iterator != nullptr) { + qep_tab->rowid_status = ROWID_PROVIDED_BY_ITERATOR_READ_CALL; + } } SJ_TMP_TABLE *sjtbl;