summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2017-05-15 09:51:01 -0700
committerIgor Babaev <igor@askmonty.org>2017-05-15 10:00:00 -0700
commite0352fb07961f09ff6481136dc22f3c0db376def (patch)
treea4e7d7869e90fe9a404b5e111e3f534b198792ef /sql
parent9495e018fbd88d094a71cb054cf468c31ebd6957 (diff)
downloadmariadb-git-e0352fb07961f09ff6481136dc22f3c0db376def.tar.gz
Fixed the bug mdev-7599.
At some conditions the function opt_sum_query() can apply MIN/MAX optimizations to to Item_sum objects of a select These optimizations becomes invalid if this select is the subquery of an IN subquery predicate that is converted to a EXISTS subquery. Thus in this case the MIX/MAX optimizations that have been applied in opt_sum_query() must be rolled back. This bug appeared in 5.3 when the code for the cost base choice between materialization and in-to-exists transformation of non-correlated IN subqueries was introduced. Before this code in-to-exists transformations were always performed before the call of opt_sum_query().
Diffstat (limited to 'sql')
-rw-r--r--sql/item_subselect.cc21
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/opt_sum.cc9
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h5
5 files changed, 37 insertions, 0 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 12337ec2b1c..e0da946d190 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -2493,6 +2493,27 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg)
DBUG_ENTER("Item_in_subselect::inject_in_to_exists_cond");
DBUG_ASSERT(thd == join_arg->thd);
+ if (select_lex->min_max_opt_list.elements)
+ {
+ /*
+ MIN/MAX optimizations have been applied to Item_sum objects
+ of the subquery this subquery predicate in opt_sum_query().
+ Injection of new condition invalidates this optimizations.
+ Thus those optimizations must be rolled back.
+ */
+ List_iterator_fast<Item_sum> it(select_lex->min_max_opt_list);
+ Item_sum *item;
+ while ((item= it++))
+ {
+ item->clear();
+ item->reset_forced_const();
+ }
+ if (where_item)
+ where_item->update_used_tables();
+ if (having_item)
+ having_item->update_used_tables();
+ }
+
if (where_item)
{
List<Item> *and_args= NULL;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 86093f5d4f5..dcc3e494f82 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -454,6 +454,7 @@ public:
used_tables_cache= 0;
forced_const= TRUE;
}
+ void reset_forced_const() { forced_const= FALSE; }
virtual bool const_item() const { return forced_const; }
virtual bool const_during_execution() const { return false; }
virtual void print(String *str, enum_query_type query_type);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index aa8b17a2c85..1a8c6be5f41 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -253,6 +253,8 @@ int opt_sum_query(THD *thd,
int error= 0;
DBUG_ENTER("opt_sum_query");
+ thd->lex->current_select->min_max_opt_list.empty();
+
if (conds)
where_tables= conds->used_tables();
@@ -444,7 +446,14 @@ int opt_sum_query(THD *thd,
item_sum->aggregator_clear();
}
else
+ {
item_sum->reset_and_add();
+ /*
+ Save a reference to the item for possible rollback
+ of the min/max optimizations for this select
+ */
+ thd->lex->current_select->min_max_opt_list.push_back(item_sum);
+ }
item_sum->make_const();
recalc_const_item= 1;
break;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index fa866bc7008..6611fd43876 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1875,6 +1875,7 @@ void st_select_lex::init_query()
leaf_tables_prep.empty();
leaf_tables.empty();
item_list.empty();
+ min_max_opt_list.empty();
join= 0;
having= prep_having= where= prep_where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b13befd8dbe..d283085886e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -766,6 +766,11 @@ public:
*/
List<Item_func_match> *ftfunc_list;
List<Item_func_match> ftfunc_list_alloc;
+ /*
+ The list of items to which MIN/MAX optimizations of opt_sum_query()
+ have been applied. Used to rollback those optimizations if it's needed.
+ */
+ List<Item_sum> min_max_opt_list;
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
List<TABLE_LIST> top_join_list; /* join list of the top level */
List<TABLE_LIST> *join_list; /* list for the currently parsed join */