summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2019-03-04 23:10:30 -0800
committerIgor Babaev <igor@askmonty.org>2019-03-04 23:11:18 -0800
commit8f4de38f65ba89c6273c15c9adb50ab762d03f59 (patch)
treeb45581c7d98404be091a090d24be19286051b7ce
parenta2fc36989e13c6f322fd22791f67e0d1275461d7 (diff)
downloadmariadb-git-8f4de38f65ba89c6273c15c9adb50ab762d03f59.tar.gz
MDEV-18467 Server crashes in fix_semijoin_strategies_for_picked_join_order
If a splittable materialized derived table / view T is used in a inner nest of an outer join with impossible ON condition then T is marked as a constant table. Yet the execution plan to build T is still searched for in spite of the fact that is not needed. So it should be set.
-rw-r--r--mysql-test/main/derived_split_innodb.result41
-rw-r--r--mysql-test/main/derived_split_innodb.test29
-rw-r--r--sql/opt_split.cc13
-rw-r--r--sql/sql_select.cc1
-rw-r--r--sql/sql_select.h3
5 files changed, 81 insertions, 6 deletions
diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result
index 21dbd494e4b..b9ed016429b 100644
--- a/mysql-test/main/derived_split_innodb.result
+++ b/mysql-test/main/derived_split_innodb.result
@@ -99,3 +99,44 @@ id select_type table type possible_keys key key_len ref rows Extra
2 LATERAL DERIVED t1 eq_ref PRIMARY PRIMARY 4 test.t2.id 1
set join_cache_level=default;
DROP TABLE t1,t2;
+#
+# Bug mdev-18467: join of grouping view and a base table as inner operand
+# of left join with on condition containing impossible range
+#
+create table t1 (f1 int, f2 int, key(f2)) engine=InnoDB;
+insert into t1 values (3,33), (7,77), (1,11);
+create table t2 (f1 int, f2 int, primary key (f1)) engine=InnoDB;
+insert into t2 values (3,33), (9,99), (1,11);
+create view v1 as
+select f1, max(f2) as f2 from t2 group by f1;
+select t.f2
+from t1
+left join
+(v1 join t1 as t on v1.f1=t.f1 and t.f2 = null)
+on t1.f1=t.f1;
+f2
+NULL
+NULL
+NULL
+explain select t.f2
+from t1
+left join
+(v1 join t1 as t on v1.f1=t.f1 and t.f2 = null)
+on t1.f1=t.f1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t const f2 NULL NULL NULL 1 Impossible ON condition
+1 PRIMARY <derived2> const key1 NULL NULL NULL 1 Impossible ON condition
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+2 DERIVED t2 ALL PRIMARY NULL NULL NULL 3 Using temporary; Using filesort
+set statement optimizer_switch='split_materialized=off' for explain select t.f2
+from t1
+left join
+(v1 join t1 as t on v1.f1=t.f1 and t.f2 = null)
+on t1.f1=t.f1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t const f2 NULL NULL NULL 1 Impossible ON condition
+1 PRIMARY <derived2> const key1 NULL NULL NULL 1 Impossible ON condition
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+2 DERIVED t2 index NULL PRIMARY 4 NULL 3
+drop view v1;
+drop table t1,t2;
diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test
index c3b3bcabede..1bf70cd8114 100644
--- a/mysql-test/main/derived_split_innodb.test
+++ b/mysql-test/main/derived_split_innodb.test
@@ -94,3 +94,32 @@ eval EXPLAIN $q;
set join_cache_level=default;
DROP TABLE t1,t2;
+
+--echo #
+--echo # Bug mdev-18467: join of grouping view and a base table as inner operand
+--echo # of left join with on condition containing impossible range
+--echo #
+
+create table t1 (f1 int, f2 int, key(f2)) engine=InnoDB;
+insert into t1 values (3,33), (7,77), (1,11);
+
+create table t2 (f1 int, f2 int, primary key (f1)) engine=InnoDB;
+insert into t2 values (3,33), (9,99), (1,11);
+
+create view v1 as
+ select f1, max(f2) as f2 from t2 group by f1;
+
+let $q=
+select t.f2
+ from t1
+ left join
+ (v1 join t1 as t on v1.f1=t.f1 and t.f2 = null)
+ on t1.f1=t.f1;
+
+eval $q;
+eval explain $q;
+eval set statement optimizer_switch='split_materialized=off' for explain $q;
+
+drop view v1;
+
+drop table t1,t2;
diff --git a/sql/opt_split.cc b/sql/opt_split.cc
index fc3f08464f4..cfac0c93544 100644
--- a/sql/opt_split.cc
+++ b/sql/opt_split.cc
@@ -1078,6 +1078,7 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
@param
spl_plan info on the splitting plan chosen for the splittable table T
remaining_tables the table T is joined just before these tables
+ is_const_table the table T is a constant table
@details
If in the final query plan the optimizer has chosen a splitting plan
@@ -1091,12 +1092,13 @@ bool JOIN::inject_best_splitting_cond(table_map remaining_tables)
*/
bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan,
- table_map remaining_tables)
+ table_map remaining_tables,
+ bool is_const_table)
{
SplM_opt_info *spl_opt_info= table->spl_opt_info;
DBUG_ASSERT(table->spl_opt_info != 0);
JOIN *md_join= spl_opt_info->join;
- if (spl_plan)
+ if (spl_plan && !is_const_table)
{
memcpy((char *) md_join->best_positions,
(char *) spl_plan->best_positions,
@@ -1113,7 +1115,7 @@ bool JOIN_TAB::fix_splitting(SplM_plan_info *spl_plan,
remaining_tables,
true);
}
- else
+ else if (md_join->save_qep)
{
md_join->restore_query_plan(md_join->save_qep);
}
@@ -1143,10 +1145,11 @@ bool JOIN::fix_all_splittings_in_plan()
{
POSITION *cur_pos= &best_positions[tablenr];
JOIN_TAB *tab= cur_pos->table;
- if (tablenr >= const_tables && tab->table->is_splittable())
+ if (tab->table->is_splittable())
{
SplM_plan_info *spl_plan= cur_pos->spl_plan;
- if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables))
+ if (tab->fix_splitting(spl_plan, all_tables & ~prev_tables,
+ tablenr < const_tables ))
return true;
}
prev_tables|= tab->table->map;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0bc27f18d47..e084ad74224 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -6689,6 +6689,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
next=tmp;
}
join->best_ref[idx]=table;
+ join->positions[idx].spl_plan= 0;
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 0e486c1fbec..57d8dab8258 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -659,7 +659,8 @@ typedef struct st_join_table {
void add_keyuses_for_splitting();
SplM_plan_info *choose_best_splitting(double record_count,
table_map remaining_tables);
- bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables);
+ bool fix_splitting(SplM_plan_info *spl_plan, table_map remaining_tables,
+ bool is_const_table);
} JOIN_TAB;