Skip to content

Commit 981a6b7

Browse files
committed
MDEV-30395 Wrong result with semijoin and Federated as outer table
The problem was that federated engine does not support comparable rowids which was not taken into account by semijoin code. Fixed by checking that we don't use semijoin with tables that does not support comparable rowids. Other things: - Fixed some typos in the code comments
1 parent 0595dd0 commit 981a6b7

File tree

6 files changed

+89
-7
lines changed

6 files changed

+89
-7
lines changed

mysql-test/suite/federated/federatedx.result

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,38 @@ DROP TABLE federated.t1;
23252325
connection slave;
23262326
DROP TABLE federated.t1;
23272327
connection default;
2328+
#
2329+
# MDEV-30395 Wrong result with semijoin and Federated as outer table
2330+
#
2331+
create server s foreign data wrapper mysql options (host "127.0.0.1", database "test", user "root", port MASTER_PORT);
2332+
CREATE TABLE t1 (a INT);
2333+
INSERT INTO t1 VALUES (3),(2),(3);
2334+
CREATE TABLE t2 (pk INT PRIMARY KEY);
2335+
INSERT INTO t2 VALUES (1),(2),(3),(4);
2336+
set @save_optimizer_switch=@@optimizer_switch;
2337+
set optimizer_switch="materialization=off";
2338+
CREATE TABLE t2_fed ENGINE=FEDERATED CONNECTION='s/t2';
2339+
explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2340+
id select_type table type possible_keys key key_len ref rows Extra
2341+
1 PRIMARY t2_fed ALL NULL NULL NULL NULL 4 Using where
2342+
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
2343+
SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2344+
pk
2345+
2
2346+
3
2347+
SET optimizer_switch='semijoin=off';
2348+
explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2349+
id select_type table type possible_keys key key_len ref rows Extra
2350+
1 PRIMARY t2_fed ALL NULL NULL NULL NULL 4 Using where
2351+
2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 3 Using where
2352+
SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2353+
pk
2354+
2
2355+
3
2356+
DROP TABLE t2_fed, t1, t2;
2357+
set @@optimizer_switch=@save_optimizer_switch;
2358+
DROP SERVER s;
2359+
# End of 10.5 tests
23282360
connection master;
23292361
DROP TABLE IF EXISTS federated.t1;
23302362
DROP DATABASE IF EXISTS federated;

mysql-test/suite/federated/federatedx.test

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,4 +2060,34 @@ connection slave;
20602060
DROP TABLE federated.t1;
20612061
connection default;
20622062

2063+
--echo #
2064+
--echo # MDEV-30395 Wrong result with semijoin and Federated as outer table
2065+
--echo #
2066+
2067+
2068+
--replace_result $MASTER_MYPORT MASTER_PORT
2069+
eval create server s foreign data wrapper mysql options (host "127.0.0.1", database "test", user "root", port $MASTER_MYPORT);
2070+
2071+
CREATE TABLE t1 (a INT);
2072+
INSERT INTO t1 VALUES (3),(2),(3);
2073+
CREATE TABLE t2 (pk INT PRIMARY KEY);
2074+
INSERT INTO t2 VALUES (1),(2),(3),(4);
2075+
2076+
set @save_optimizer_switch=@@optimizer_switch;
2077+
set optimizer_switch="materialization=off";
2078+
2079+
CREATE TABLE t2_fed ENGINE=FEDERATED CONNECTION='s/t2';
2080+
explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2081+
SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2082+
SET optimizer_switch='semijoin=off';
2083+
explain SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2084+
SELECT * FROM t2_fed WHERE pk IN ( SELECT a FROM t1 );
2085+
2086+
DROP TABLE t2_fed, t1, t2;
2087+
set @@optimizer_switch=@save_optimizer_switch;
2088+
2089+
DROP SERVER s;
2090+
2091+
--echo # End of 10.5 tests
2092+
20632093
source include/federated_cleanup.inc;

sql/handler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,9 @@ enum chf_create_flags {
356356
Rowid's are not comparable. This is set if the rowid is unique to the
357357
current open handler, like it is with federated where the rowid is a
358358
pointer to a local result set buffer. The effect of having this set is
359-
that the optimizer will not consirer the following optimizations for
359+
that the optimizer will not consider the following optimizations for
360360
the table:
361-
ror scans or filtering
361+
ror scans, filtering or duplicate weedout
362362
*/
363363
#define HA_NON_COMPARABLE_ROWID (1ULL << 60)
364364

sql/opt_subselect.cc

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,17 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
664664
DBUG_RETURN(-1);
665665
}
666666
}
667+
/* Check if any table is not supporting comparable rowids */
668+
{
669+
List_iterator_fast<TABLE_LIST> li(select_lex->outer_select()->leaf_tables);
670+
TABLE_LIST *tbl;
671+
while ((tbl = li++))
672+
{
673+
TABLE *table= tbl->table;
674+
if (table && table->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID)
675+
join->not_usable_rowid_map|= table->map;
676+
}
677+
}
667678

668679
DBUG_PRINT("info", ("Checking if subq can be converted to semi-join"));
669680
/*
@@ -683,8 +694,11 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
683694
9. Parent select is not a table-less select
684695
10. Neither parent nor child select have STRAIGHT_JOIN option.
685696
11. It is first optimisation (the subquery could be moved from ON
686-
clause during first optimisation and then be considered for SJ
687-
on the second when it is too late)
697+
clause during first optimisation and then be considered for SJ
698+
on the second when it is too late)
699+
12. All tables supports comparable rowids.
700+
This is needed for DuplicateWeedout strategy to work (which
701+
is the catch-all semi-join strategy so it must be applicable).
688702
*/
689703
if (optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
690704
in_subs && // 1
@@ -699,7 +713,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
699713
!((join->select_options | // 10
700714
select_lex->outer_select()->join->select_options) // 10
701715
& SELECT_STRAIGHT_JOIN) && // 10
702-
select_lex->first_cond_optimization) // 11
716+
select_lex->first_cond_optimization && // 11
717+
join->not_usable_rowid_map == 0) // 12
703718
{
704719
DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
705720

@@ -3544,6 +3559,9 @@ bool Duplicate_weedout_picker::check_qep(JOIN *join,
35443559
}
35453560
else
35463561
{
3562+
/* Ensure that table supports comparable rowids */
3563+
DBUG_ASSERT(!(p->table->table->file->ha_table_flags() & HA_NON_COMPARABLE_ROWID));
3564+
35473565
sj_outer_fanout= COST_MULT(sj_outer_fanout, p->records_read);
35483566
temptable_rec_size += p->table->table->file->ref_length;
35493567
}

sql/sql_select.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2309,7 +2309,7 @@ JOIN::optimize_inner()
23092309
/*
23102310
We have to remove constants and duplicates from group_list before
23112311
calling make_join_statistics() as this may call get_best_group_min_max()
2312-
which needs a simplfied group_list.
2312+
which needs a simplified group_list.
23132313
*/
23142314
if (group_list && table_count == 1)
23152315
{

sql/sql_select.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,8 @@ class JOIN :public Sql_alloc
12381238
table_map outer_join;
12391239
/* Bitmap of tables used in the select list items */
12401240
table_map select_list_used_tables;
1241+
/* Tables that has HA_NON_COMPARABLE_ROWID (does not support rowid) set */
1242+
table_map not_usable_rowid_map;
12411243
ha_rows send_records,found_records,join_examined_rows;
12421244

12431245
/*
@@ -1550,7 +1552,7 @@ class JOIN :public Sql_alloc
15501552
table_count= 0;
15511553
top_join_tab_count= 0;
15521554
const_tables= 0;
1553-
const_table_map= found_const_table_map= 0;
1555+
const_table_map= found_const_table_map= not_usable_rowid_map= 0;
15541556
aggr_tables= 0;
15551557
eliminated_tables= 0;
15561558
join_list= 0;

0 commit comments

Comments
 (0)