Skip to content

Commit e6472e8

Browse files
Sergey GlukhovSergey Glukhov
Sergey Glukhov
authored and
Sergey Glukhov
committed
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).
1 parent 9a8f22f commit e6472e8

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

mysql-test/r/explain.result

+46
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,50 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1;
251251
id select_type table type possible_keys key key_len ref rows Extra
252252
1 SIMPLE t1 ref c2,c2_2 c2 10 const,const 3 Using where
253253
DROP TABLE t1;
254+
#
255+
# Bug#56814 Explain + subselect + fulltext crashes server
256+
#
257+
CREATE TABLE t1(f1 VARCHAR(6) NOT NULL,
258+
FULLTEXT KEY(f1),UNIQUE(f1));
259+
INSERT INTO t1 VALUES ('test');
260+
EXPLAIN SELECT 1 FROM t1
261+
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST (""))
262+
WHERE t1.f1 GROUP BY t1.f1));
263+
id select_type table type possible_keys key key_len ref rows Extra
264+
1 PRIMARY t1 system NULL NULL NULL NULL 1
265+
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
266+
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
267+
PREPARE stmt FROM
268+
'EXPLAIN SELECT 1 FROM t1
269+
WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a
270+
ON (MATCH(t1.f1) AGAINST (""))
271+
WHERE t1.f1 GROUP BY t1.f1))';
272+
EXECUTE stmt;
273+
id select_type table type possible_keys key key_len ref rows Extra
274+
1 PRIMARY t1 system NULL NULL NULL NULL 1
275+
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
276+
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
277+
EXECUTE stmt;
278+
id select_type table type possible_keys key key_len ref rows Extra
279+
1 PRIMARY t1 system NULL NULL NULL NULL 1
280+
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
281+
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
282+
DEALLOCATE PREPARE stmt;
283+
PREPARE stmt FROM
284+
'EXPLAIN SELECT 1 FROM t1
285+
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a
286+
ON (MATCH(t1.f1) AGAINST (""))
287+
WHERE t1.f1 GROUP BY t1.f1))';
288+
EXECUTE stmt;
289+
id select_type table type possible_keys key key_len ref rows Extra
290+
1 PRIMARY t1 system NULL NULL NULL NULL 1
291+
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
292+
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
293+
EXECUTE stmt;
294+
id select_type table type possible_keys key key_len ref rows Extra
295+
1 PRIMARY t1 system NULL NULL NULL NULL 1
296+
2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort
297+
2 SUBQUERY t1 fulltext f1 f1 0 1 Using where
298+
DEALLOCATE PREPARE stmt;
299+
DROP TABLE t1;
254300
End of 5.1 tests.

mysql-test/t/explain.test

+36
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,40 @@ EXPLAIN SELECT c1 FROM t1 WHERE c2 = 1 AND c4 = 1 AND c5 = 1;
228228

229229
DROP TABLE t1;
230230

231+
--echo #
232+
--echo # Bug#56814 Explain + subselect + fulltext crashes server
233+
--echo #
234+
235+
CREATE TABLE t1(f1 VARCHAR(6) NOT NULL,
236+
FULLTEXT KEY(f1),UNIQUE(f1));
237+
INSERT INTO t1 VALUES ('test');
238+
239+
EXPLAIN SELECT 1 FROM t1
240+
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a ON (MATCH(t1.f1) AGAINST (""))
241+
WHERE t1.f1 GROUP BY t1.f1));
242+
243+
PREPARE stmt FROM
244+
'EXPLAIN SELECT 1 FROM t1
245+
WHERE 1 > ALL((SELECT 1 FROM t1 RIGHT OUTER JOIN t1 a
246+
ON (MATCH(t1.f1) AGAINST (""))
247+
WHERE t1.f1 GROUP BY t1.f1))';
248+
249+
EXECUTE stmt;
250+
EXECUTE stmt;
251+
252+
DEALLOCATE PREPARE stmt;
253+
254+
PREPARE stmt FROM
255+
'EXPLAIN SELECT 1 FROM t1
256+
WHERE 1 > ALL((SELECT 1 FROM t1 JOIN t1 a
257+
ON (MATCH(t1.f1) AGAINST (""))
258+
WHERE t1.f1 GROUP BY t1.f1))';
259+
260+
EXECUTE stmt;
261+
EXECUTE stmt;
262+
263+
DEALLOCATE PREPARE stmt;
264+
265+
DROP TABLE t1;
266+
231267
--echo End of 5.1 tests.

sql/item_subselect.cc

+10-5
Original file line numberDiff line numberDiff line change
@@ -1906,21 +1906,26 @@ int subselect_single_select_engine::exec()
19061906
DBUG_RETURN(join->error ? join->error : 1);
19071907
}
19081908
if (!select_lex->uncacheable && thd->lex->describe &&
1909-
!(join->select_options & SELECT_DESCRIBE) &&
1910-
join->need_tmp)
1909+
!(join->select_options & SELECT_DESCRIBE))
19111910
{
19121911
item->update_used_tables();
19131912
if (item->const_item())
19141913
{
1914+
/*
1915+
It's necessary to keep original JOIN table because
1916+
create_sort_index() function may overwrite original
1917+
JOIN_TAB::type and wrong optimization method can be
1918+
selected on re-execution.
1919+
*/
1920+
select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
1921+
select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
19151922
/*
19161923
Force join->join_tmp creation, because this subquery will be replaced
19171924
by a simple select from the materialization temp table by optimize()
19181925
called by EXPLAIN and we need to preserve the initial query structure
19191926
so we can display it.
19201927
*/
1921-
select_lex->uncacheable|= UNCACHEABLE_EXPLAIN;
1922-
select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN;
1923-
if (join->init_save_join_tab())
1928+
if (join->need_tmp && join->init_save_join_tab())
19241929
DBUG_RETURN(1); /* purecov: inspected */
19251930
}
19261931
}

sql/sql_select.cc

+14
Original file line numberDiff line numberDiff line change
@@ -2490,6 +2490,13 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
24902490
{
24912491
DBUG_RETURN(TRUE);
24922492
}
2493+
/*
2494+
Original join tabs might be overwritten at first
2495+
subselect execution. So we need to restore them.
2496+
*/
2497+
Item_subselect *subselect= select_lex->master_unit()->item;
2498+
if (subselect && subselect->is_uncacheable() && join->reinit())
2499+
DBUG_RETURN(TRUE);
24932500
}
24942501
else
24952502
{
@@ -8825,6 +8832,13 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
88258832
that reject nulls => the outer join can be replaced by an inner join.
88268833
*/
88278834
table->outer_join= 0;
8835+
/*
8836+
Update TABLE::maybe_null field as it could have
8837+
the value(maybe_null==TRUE) based on the assumption
8838+
that this join is outer(see setup_table_map() func).
8839+
*/
8840+
if (table->table)
8841+
table->table->maybe_null= FALSE;
88288842
if (table->on_expr)
88298843
{
88308844
/* Add on expression to the where condition. */

0 commit comments

Comments
 (0)