Commit d0ac4e2c authored by Sergey Glukhov's avatar Sergey Glukhov

Bug#56814 Explain + subselect + fulltext crashes server

create_sort_index() function overwrites original JOIN_TAB::type field.
At re-execution of subquery overwritten JOIN_TAB::type(JT_ALL) is
used instead of JT_FT. It misleads test_if_skip_sort_order() and
the function tries to find suitable key for the order that should
not be allowed for FULLTEXT(JT_FT) table.
The fix is to restore JOIN_TAB strucures for subselect on re-execution
for EXPLAIN.
Additional fix:
Update TABLE::maybe_null field which
affects list_contains_unique_index() behaviour as it
could have the value(maybe_null==TRUE) based on the
assumption that this join is outer
(see setup_table_map() func).


mysql-test/r/explain.result:
  test case
mysql-test/t/explain.test:
  test case
sql/item_subselect.cc:
  Make subquery uncacheable in case of EXPLAIN. It allows to keep
  original JOIN_TAB::type(see JOIN::save_join_tab) and restore it
  on re-execution.
sql/sql_select.cc:
  -restore JOIN_TAB strucures for subselect on re-execution for EXPLAIN
  -Update TABLE::maybe_null field as it could have
   the value(maybe_null==TRUE) based on the assumption
   that this join is outer(see setup_table_map() func).
   This change is not related to the crash problem but
   affects EXPLAIN results in the test case.
parent 127c721c
...@@ -251,4 +251,50 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1; ...@@ -251,4 +251,50 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref c2,c2_2 c2 10 const,const 3 Using where 1 SIMPLE t1 ref c2,c2_2 c2 10 const,const 3 Using where
DROP TABLE t1; DROP TABLE t1;
#
# Bug#56814 Explain + subselect + fulltext crashes server
#
CREATE TABLE t1(f1 VARCHAR(6) NOT NULL,
FULLTEXT KEY(f1),UNIQUE(f1));
INSERT INTO t1 VALUES ('test');
EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
PREPARE stmt FROM
'EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a
ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1))';
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM
'EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a
ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1))';
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
EXECUTE stmt;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 system NULL NULL NULL NULL 1
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
End of 5.1 tests. End of 5.1 tests.
...@@ -228,4 +228,40 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1; ...@@ -228,4 +228,40 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Bug#56814 Explain + subselect + fulltext crashes server
--echo #
CREATE TABLE t1(f1 VARCHAR(6) NOT NULL,
FULLTEXT KEY(f1),UNIQUE(f1));
INSERT INTO t1 VALUES ('test');
EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1));
PREPARE stmt FROM
'EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a
ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1))';
EXECUTE stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
PREPARE stmt FROM
'EXPLAIN SELECT 1 FROM t1
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a
ON (MATCH(t1.f1) AGAINST (""))
WHERE t1.f1 GROUP BY t1.f1))';
EXECUTE stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
--echo End of 5.1 tests. --echo End of 5.1 tests.
...@@ -1906,21 +1906,26 @@ int subselect_single_select_engine::exec() ...@@ -1906,21 +1906,26 @@ int subselect_single_select_engine::exec()
DBUG_RETURN(join->error ? join->error : 1); DBUG_RETURN(join->error ? join->error : 1);
} }
if (!select_lex->uncacheable && thd->lex->describe && if (!select_lex->uncacheable && thd->lex->describe &&
!(join->select_options & SELECT_DESCRIBE) && !(join->select_options & SELECT_DESCRIBE))
join->need_tmp)
{ {
item->update_used_tables(); item->update_used_tables();
if (item->const_item()) if (item->const_item())
{ {
/*
It's necessary to keep original JOIN table because
create_sort_index() function may overwrite original
JOIN_TAB::type and wrong optimization method can be
selected on re-execution.
*/
select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
/* /*
Force join->join_tmp creation, because this subquery will be replaced Force join->join_tmp creation, because this subquery will be replaced
by a simple select from the materialization temp table by optimize() by a simple select from the materialization temp table by optimize()
called by EXPLAIN and we need to preserve the initial query structure called by EXPLAIN and we need to preserve the initial query structure
so we can display it. so we can display it.
*/ */
select_lex->uncacheable|= UNCACHEABLE_EXPLAIN; if (join->need_tmp && join->init_save_join_tab())
select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
if (join->init_save_join_tab())
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
} }
} }
......
...@@ -2490,6 +2490,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array, ...@@ -2490,6 +2490,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
{ {
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
/*
Original join tabs might be overwritten at first
subselect execution. So we need to restore them.
*/
Item_subselect *subselect= select_lex->master_unit()->item;
if (subselect && subselect->is_uncacheable() && join->reinit())
DBUG_RETURN(TRUE);
} }
else else
{ {
...@@ -8825,6 +8832,13 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) ...@@ -8825,6 +8832,13 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
that reject nulls => the outer join can be replaced by an inner join. that reject nulls => the outer join can be replaced by an inner join.
*/ */
table->outer_join= 0; table->outer_join= 0;
/*
Update TABLE::maybe_null field as it could have
the value(maybe_null==TRUE) based on the assumption
that this join is outer(see setup_table_map() func).
*/
if (table->table)
table->table->maybe_null= FALSE;
if (table->on_expr) if (table->on_expr)
{ {
/* Add on expression to the where condition. */ /* Add on expression to the where condition. */
......
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