summaryrefslogtreecommitdiff
path: root/sql/item_subselect.cc
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2017-04-20 13:09:31 -0700
committerIgor Babaev <igor@askmonty.org>2017-04-21 09:33:36 -0700
commit54a995cd2206995f6dd675cabdce12a4b7ff7540 (patch)
tree432bee02fb5e533f1216a9c84f1ede1f4a2a87ea /sql/item_subselect.cc
parent14d124880f432d5d4a29e7ec79b0d2b922ec52ae (diff)
downloadmariadb-git-54a995cd2206995f6dd675cabdce12a4b7ff7540.tar.gz
Fixed the bug mdev-12519.
This patch fixed some problems that occurred with subqueries that contained directly or indirectly recursive references to recursive CTEs. 1. A [NOT] IN predicate with a constant left operand and a non-correlated subquery as the right operand used in the specification of a recursive CTE was considered as a constant predicate and was evaluated only once. Now such a predicate is re-evaluated after every iteration of the process that produces the records of the recursive CTE. 2. The Exists-To-IN transformation could be applied to [NOT] IN predicates with recursive references. This opened a possibility of materialization for the subqueries used as right operands. Yet, materialization is prohibited for the subqueries if they contain a recursive reference. Now the Exists-To-IN transformation cannot be applied for subquery predicates with recursive references. The function st_select_lex::check_subqueries_with_recursive_references() is called now only for the first execution of the SELECT.
Diffstat (limited to 'sql/item_subselect.cc')
-rw-r--r--sql/item_subselect.cc34
1 files changed, 28 insertions, 6 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 76c754d5627..d144dddf764 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -40,6 +40,7 @@
#include "set_var.h"
#include "sql_select.h"
#include "sql_parse.h" // check_stack_overrun
+#include "sql_cte.h"
#include "sql_test.h"
double get_post_group_estimate(JOIN* join, double join_op_rows);
@@ -312,7 +313,8 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
else
goto end;
- if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
+ if ((uncacheable= engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) ||
+ with_recursive_reference)
{
const_item_cache= 0;
if (uncacheable & UNCACHEABLE_RAND)
@@ -917,7 +919,7 @@ table_map Item_subselect::used_tables() const
bool Item_subselect::const_item() const
{
DBUG_ASSERT(thd);
- return (thd->lex->context_analysis_only ?
+ return (thd->lex->context_analysis_only || with_recursive_reference ?
FALSE :
forced_const || const_item_cache);
}
@@ -937,7 +939,8 @@ void Item_subselect::update_used_tables()
if (!(engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
{
// did all used tables become static?
- if (!(used_tables_cache & ~engine->upper_select_const_tables()))
+ if (!(used_tables_cache & ~engine->upper_select_const_tables()) &&
+ ! with_recursive_reference)
const_item_cache= 1;
}
}
@@ -1735,7 +1738,7 @@ bool Item_in_subselect::val_bool()
if (forced_const)
return value;
DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) ||
- ! engine->is_executed());
+ ! engine->is_executed() || with_recursive_reference);
null_value= was_null= FALSE;
if (exec())
{
@@ -2828,7 +2831,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
join->having ||
first_select->with_sum_func ||
!first_select->leaf_tables.elements||
- !join->conds)
+ !join->conds ||
+ with_recursive_reference)
DBUG_RETURN(FALSE);
DBUG_ASSERT(first_select->order_list.elements == 0 &&
@@ -3480,6 +3484,11 @@ int subselect_single_select_engine::get_identifier()
return select_lex->select_number;
}
+void subselect_single_select_engine::force_reexecution()
+{
+ executed= false;
+}
+
void subselect_single_select_engine::cleanup()
{
DBUG_ENTER("subselect_single_select_engine::cleanup");
@@ -3508,6 +3517,11 @@ bool subselect_union_engine::is_executed() const
return unit->executed;
}
+void subselect_union_engine::force_reexecution()
+{
+ unit->executed= false;
+}
+
/*
Check if last execution of the subquery engine produced any rows
@@ -3827,7 +3841,8 @@ int subselect_single_select_engine::exec()
tab->read_record.read_record= tab->save_read_record;
}
executed= 1;
- if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN))
+ if (!(uncacheable() & ~UNCACHEABLE_EXPLAIN) &&
+ !item->with_recursive_reference)
item->make_const();
thd->where= save_where;
thd->lex->current_select= save_select;
@@ -6674,6 +6689,13 @@ void subselect_table_scan_engine::cleanup()
}
+void Item_subselect::register_as_with_rec_ref(With_element *with_elem)
+{
+ with_elem->sq_with_rec_ref.link_in_list(this, &this->next_with_rec_ref);
+ with_recursive_reference= true;
+}
+
+
/*
Create an execution tracker for the expression cache we're using for this
subselect; add the tracker to the query plan.