Commit a52d3aa8 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops

Do not set 'optimized' flag until whole optimization procedure is finished.
parent e6a64e8f
...@@ -7157,5 +7157,21 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7157,5 +7157,21 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
...@@ -7157,8 +7157,24 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7157,8 +7157,24 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
set optimizer_switch=default; set optimizer_switch=default;
select @@optimizer_switch like '%exists_to_in=off%'; select @@optimizer_switch like '%exists_to_in=off%';
@@optimizer_switch like '%exists_to_in=off%' @@optimizer_switch like '%exists_to_in=off%'
......
...@@ -7150,8 +7150,24 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7150,8 +7150,24 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
set optimizer_switch=default; set optimizer_switch=default;
select @@optimizer_switch like '%materialization=on%'; select @@optimizer_switch like '%materialization=on%';
@@optimizer_switch like '%materialization=on%' @@optimizer_switch like '%materialization=on%'
......
...@@ -7148,6 +7148,22 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7148,6 +7148,22 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
...@@ -7163,8 +7163,24 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7163,8 +7163,24 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
set optimizer_switch=default; set optimizer_switch=default;
select @@optimizer_switch like '%subquery_cache=on%'; select @@optimizer_switch like '%subquery_cache=on%';
@@optimizer_switch like '%subquery_cache=on%' @@optimizer_switch like '%subquery_cache=on%'
......
...@@ -7148,7 +7148,23 @@ INSERT INTO t1 VALUES ('foo'); ...@@ -7148,7 +7148,23 @@ INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
f f
foo foo
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
f
foo
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
#
# MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
#
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
f1 f2 f3
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
f1 f2 f3
DROP TABLE t1, t2;
SET NAMES default;
End of 10.1 tests
set @optimizer_switch_for_subselect_test=null; set @optimizer_switch_for_subselect_test=null;
set @join_cache_level_for_subselect_test=NULL; set @join_cache_level_for_subselect_test=NULL;
...@@ -6009,5 +6009,22 @@ SET NAMES utf8; ...@@ -6009,5 +6009,22 @@ SET NAMES utf8;
CREATE TABLE t1 (f VARCHAR(8)) ENGINE=MyISAM; CREATE TABLE t1 (f VARCHAR(8)) ENGINE=MyISAM;
INSERT INTO t1 VALUES ('foo'); INSERT INTO t1 VALUES ('foo');
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' ); SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar' UNION SELECT 'baz' );
SELECT f FROM t1 WHERE f > ALL ( SELECT 'bar');
drop table t1; drop table t1;
SET NAMES default; SET NAMES default;
--echo #
--echo # MDEV-10045: Server crashes in Time_and_counter_tracker::incr_loops
--echo #
SET NAMES utf8;
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT UNSIGNED) ENGINE=MyISAM;
CREATE TABLE t2 (f3 INT) ENGINE=MyISAM;
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo' UNION SELECT 'bar' );
SELECT * FROM t1, t2 WHERE f3 = f2 AND f1 > ANY ( SELECT 'foo');
DROP TABLE t1, t2;
SET NAMES default;
--echo End of 10.1 tests
...@@ -560,6 +560,21 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent, ...@@ -560,6 +560,21 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
bool Item_subselect::is_expensive() bool Item_subselect::is_expensive()
{ {
double examined_rows= 0; double examined_rows= 0;
bool all_are_simple= true;
/* check extremely simple select */
if (!unit->first_select()->next_select()) // no union
{
/*
such single selects works even without optimization because
can not makes loops
*/
SELECT_LEX *sl= unit->first_select();
JOIN *join = sl->join;
if (join && !join->tables_list && !sl->first_inner_unit())
return false;
}
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
{ {
...@@ -569,23 +584,27 @@ bool Item_subselect::is_expensive() ...@@ -569,23 +584,27 @@ bool Item_subselect::is_expensive()
if (!cur_join) if (!cur_join)
return true; return true;
/* very simple subquery */
if (!cur_join->tables_list && !sl->first_inner_unit())
return false;
/* /*
If the subquery is not optimised or in the process of optimization If the subquery is not optimised or in the process of optimization
it supposed to be expensive it supposed to be expensive
*/ */
if (!cur_join->optimized) if (cur_join->optimization_state != JOIN::OPTIMIZATION_DONE)
return true; return true;
if (!cur_join->tables_list && !sl->first_inner_unit())
continue;
/* /*
Subqueries whose result is known after optimization are not expensive. Subqueries whose result is known after optimization are not expensive.
Such subqueries have all tables optimized away, thus have no join plan. Such subqueries have all tables optimized away, thus have no join plan.
*/ */
if ((cur_join->zero_result_cause || !cur_join->tables_list)) if ((cur_join->zero_result_cause || !cur_join->tables_list))
return false; continue;
/*
This is not simple SELECT in union so we can not go by simple condition
*/
all_are_simple= false;
/* /*
If a subquery is not optimized we cannot estimate its cost. A subquery is If a subquery is not optimized we cannot estimate its cost. A subquery is
...@@ -606,7 +625,8 @@ bool Item_subselect::is_expensive() ...@@ -606,7 +625,8 @@ bool Item_subselect::is_expensive()
examined_rows+= cur_join->get_examined_rows(); examined_rows+= cur_join->get_examined_rows();
} }
return (examined_rows > thd->variables.expensive_subquery_limit); return !all_are_simple &&
(examined_rows > thd->variables.expensive_subquery_limit);
} }
...@@ -3672,7 +3692,7 @@ int subselect_single_select_engine::exec() ...@@ -3672,7 +3692,7 @@ int subselect_single_select_engine::exec()
SELECT_LEX *save_select= thd->lex->current_select; SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex; thd->lex->current_select= select_lex;
if (!join->optimized) if (join->optimization_state == JOIN::NOT_OPTIMIZED)
{ {
SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX_UNIT *unit= select_lex->master_unit();
...@@ -5321,7 +5341,8 @@ int subselect_hash_sj_engine::exec() ...@@ -5321,7 +5341,8 @@ int subselect_hash_sj_engine::exec()
*/ */
thd->lex->current_select= materialize_engine->select_lex; thd->lex->current_select= materialize_engine->select_lex;
/* The subquery should be optimized, and materialized only once. */ /* The subquery should be optimized, and materialized only once. */
DBUG_ASSERT(materialize_join->optimized && !is_materialized); DBUG_ASSERT(materialize_join->optimization_state == JOIN::OPTIMIZATION_DONE &&
!is_materialized);
materialize_join->exec(); materialize_join->exec();
if ((res= MY_TEST(materialize_join->error || thd->is_fatal_error || if ((res= MY_TEST(materialize_join->error || thd->is_fatal_error ||
thd->is_error()))) thd->is_error())))
......
...@@ -694,7 +694,7 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -694,7 +694,7 @@ JOIN::prepare(Item ***rref_pointer_array,
DBUG_ENTER("JOIN::prepare"); DBUG_ENTER("JOIN::prepare");
// to prevent double initialization on EXPLAIN // to prevent double initialization on EXPLAIN
if (optimized) if (optimization_state != JOIN::NOT_OPTIMIZED)
DBUG_RETURN(0); DBUG_RETURN(0);
conds= conds_init; conds= conds_init;
...@@ -1032,24 +1032,13 @@ bool JOIN::prepare_stage2() ...@@ -1032,24 +1032,13 @@ bool JOIN::prepare_stage2()
int JOIN::optimize() int JOIN::optimize()
{ {
bool was_optimized= optimized; // to prevent double initialization on EXPLAIN
int res= optimize_inner(); if (optimization_state != JOIN::NOT_OPTIMIZED)
/* return FALSE;
If we're inside a non-correlated subquery, this function may be optimization_state= JOIN::OPTIMIZATION_IN_PROGRESS;
called for the second time after the subquery has been executed
and deleted. The second call will not produce a valid query plan, it will
short-circuit because optimized==TRUE.
"was_optimized != optimized" is here to handle this case:
- first optimization starts, gets an error (from a const. cheap
subquery), returns 1
- another JOIN::optimize() call made, and now join->optimize() will
return 0, even though we never had a query plan.
Can have QEP_NOT_PRESENT_YET for degenerate queries (for example, int res= optimize_inner();
SELECT * FROM tbl LIMIT 0) if (!res && have_query_plan != QEP_DELETED)
*/
if (was_optimized != optimized && !res && have_query_plan != QEP_DELETED)
{ {
create_explain_query_if_not_exists(thd->lex, thd->mem_root); create_explain_query_if_not_exists(thd->lex, thd->mem_root);
have_query_plan= QEP_AVAILABLE; have_query_plan= QEP_AVAILABLE;
...@@ -1058,6 +1047,7 @@ int JOIN::optimize() ...@@ -1058,6 +1047,7 @@ int JOIN::optimize()
!skip_sort_order && !no_order && (order || group_list), !skip_sort_order && !no_order && (order || group_list),
select_distinct); select_distinct);
} }
optimization_state= JOIN::OPTIMIZATION_DONE;
return res; return res;
} }
...@@ -1083,10 +1073,6 @@ JOIN::optimize_inner() ...@@ -1083,10 +1073,6 @@ JOIN::optimize_inner()
DBUG_ENTER("JOIN::optimize"); DBUG_ENTER("JOIN::optimize");
do_send_rows = (unit->select_limit_cnt) ? 1 : 0; do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
// to prevent double initialization on EXPLAIN
if (optimized)
DBUG_RETURN(0);
optimized= 1;
DEBUG_SYNC(thd, "before_join_optimize"); DEBUG_SYNC(thd, "before_join_optimize");
THD_STAGE_INFO(thd, stage_optimizing); THD_STAGE_INFO(thd, stage_optimizing);
...@@ -2060,7 +2046,7 @@ int JOIN::init_execution() ...@@ -2060,7 +2046,7 @@ int JOIN::init_execution()
{ {
DBUG_ENTER("JOIN::init_execution"); DBUG_ENTER("JOIN::init_execution");
DBUG_ASSERT(optimized); DBUG_ASSERT(optimization_state == JOIN::OPTIMIZATION_DONE);
DBUG_ASSERT(!(select_options & SELECT_DESCRIBE)); DBUG_ASSERT(!(select_options & SELECT_DESCRIBE));
initialized= true; initialized= true;
......
...@@ -1290,7 +1290,8 @@ class JOIN :public Sql_alloc ...@@ -1290,7 +1290,8 @@ class JOIN :public Sql_alloc
enum join_optimization_state { NOT_OPTIMIZED=0, enum join_optimization_state { NOT_OPTIMIZED=0,
OPTIMIZATION_IN_PROGRESS=1, OPTIMIZATION_IN_PROGRESS=1,
OPTIMIZATION_DONE=2}; OPTIMIZATION_DONE=2};
bool optimized; ///< flag to avoid double optimization in EXPLAIN // state of JOIN optimization
enum join_optimization_state optimization_state;
bool initialized; ///< flag to avoid double init_execution calls bool initialized; ///< flag to avoid double init_execution calls
Explain_select *explain; Explain_select *explain;
...@@ -1378,7 +1379,7 @@ class JOIN :public Sql_alloc ...@@ -1378,7 +1379,7 @@ class JOIN :public Sql_alloc
ref_pointer_array= items0= items1= items2= items3= 0; ref_pointer_array= items0= items1= items2= items3= 0;
ref_pointer_array_size= 0; ref_pointer_array_size= 0;
zero_result_cause= 0; zero_result_cause= 0;
optimized= 0; optimization_state= JOIN::NOT_OPTIMIZED;
have_query_plan= QEP_NOT_PRESENT_YET; have_query_plan= QEP_NOT_PRESENT_YET;
initialized= 0; initialized= 0;
cleaned= 0; cleaned= 0;
......
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