diff options
author | Igor Babaev <igor@askmonty.org> | 2017-04-20 13:09:31 -0700 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2017-04-21 09:33:36 -0700 |
commit | 54a995cd2206995f6dd675cabdce12a4b7ff7540 (patch) | |
tree | 432bee02fb5e533f1216a9c84f1ede1f4a2a87ea /sql/item_subselect.cc | |
parent | 14d124880f432d5d4a29e7ec79b0d2b922ec52ae (diff) | |
download | mariadb-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.cc | 34 |
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. |