diff options
author | Galina Shalygina <galashalygina@gmail.com> | 2016-05-09 23:39:10 +0300 |
---|---|---|
committer | Galina Shalygina <galashalygina@gmail.com> | 2016-05-09 23:39:10 +0300 |
commit | f516b966e131177244941319c553e138fbf9f6ff (patch) | |
tree | 912b7330543fa95cd7f9dd4c53723a63ce5f7e88 /sql/sql_cte.cc | |
parent | 5703d2680c0d4884d86b7541cd9b46943f929a2d (diff) | |
download | mariadb-git-f516b966e131177244941319c553e138fbf9f6ff.tar.gz |
Main patch for mdev-9864
Diffstat (limited to 'sql/sql_cte.cc')
-rw-r--r-- | sql/sql_cte.cc | 304 |
1 files changed, 281 insertions, 23 deletions
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index 77f0bcf04ba..04d53495400 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -21,14 +21,17 @@ true on failure */ -bool check_dependencies_in_with_clauses(With_clause *with_clauses_list) +bool check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list) { for (With_clause *with_clause= with_clauses_list; with_clause; with_clause= with_clause->next_with_clause) { - if (with_clause->check_dependencies()) + if (with_clause->check_dependencies(thd)) return true; + if (with_clause->check_anchors()) + return true; + with_clause->move_anchors_ahead(); } return false; } @@ -57,7 +60,7 @@ bool check_dependencies_in_with_clauses(With_clause *with_clauses_list) false otherwise */ -bool With_clause::check_dependencies() +bool With_clause::check_dependencies(THD *thd) { if (dependencies_are_checked) return false; @@ -84,18 +87,23 @@ bool With_clause::check_dependencies() return true; } } - with_elem->check_dependencies_in_unit(with_elem->spec); + if (with_elem->check_dependencies_in_spec(thd)) + return true; } /* Build the transitive closure of the direct dependencies found above */ for (With_element *with_elem= first_elem; with_elem != NULL; with_elem= with_elem->next_elem) + with_elem->derived_dep_map= with_elem->base_dep_map; + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) { table_map with_elem_map= with_elem->get_elem_map(); for (With_element *elem= first_elem; elem != NULL; elem= elem->next_elem) { - if (elem->dependency_map & with_elem_map) - elem->dependency_map |= with_elem->dependency_map; + if (elem->derived_dep_map & with_elem_map) + elem->derived_dep_map |= with_elem->derived_dep_map; } } @@ -107,7 +115,7 @@ bool With_clause::check_dependencies() with_elem != NULL; with_elem= with_elem->next_elem) { - if (with_elem->dependency_map & with_elem->get_elem_map()) + if (with_elem->derived_dep_map & with_elem->get_elem_map()) with_elem->is_recursive= true; } for (With_element *with_elem= first_elem; @@ -115,10 +123,12 @@ bool With_clause::check_dependencies() with_elem= with_elem->next_elem) { if (with_elem->is_recursive) - { + { +#if 0 my_error(ER_RECURSIVE_QUERY_IN_WITH_CLAUSE, MYF(0), with_elem->query_name->str); return true; +#endif } } @@ -152,7 +162,39 @@ bool With_clause::check_dependencies() } -/** +bool With_element::check_dependencies_in_spec(THD *thd) +{ + for (st_select_lex *sl= spec->first_select(); sl; sl= sl->next_select()) + { + check_dependencies_in_select(sl, sl->with_dep); + base_dep_map|= sl->with_dep; + } + return false; +} + + +void With_element::check_dependencies_in_select(st_select_lex *sl, table_map &dep_map) +{ + for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local) + { + tbl->with_internal_reference_map= 0; + if (!tbl->with) + tbl->with= owner->find_table_def(tbl); + if (!tbl->with && tbl->select_lex) + tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl); + if (tbl->with && tbl->with->owner== this->owner) + { + dep_map|= tbl->with->get_elem_map(); + tbl->with_internal_reference_map= get_elem_map(); + } + } + st_select_lex_unit *inner_unit= sl->first_inner_unit(); + for (; inner_unit; inner_unit= inner_unit->next_unit()) + check_dependencies_in_unit(inner_unit, dep_map); +} + + + /** @brief Check dependencies on the sibling with tables used in the given unit @@ -166,24 +208,102 @@ bool With_clause::check_dependencies() dependency_map of this element. */ -void With_element::check_dependencies_in_unit(st_select_lex_unit *unit) +void With_element::check_dependencies_in_unit(st_select_lex_unit *unit, + table_map &dep_map) { st_select_lex *sl= unit->first_select(); for (; sl; sl= sl->next_select()) { - for (TABLE_LIST *tbl= sl->table_list.first; tbl; tbl= tbl->next_local) + check_dependencies_in_select(sl, dep_map); + } +} + + +bool With_clause::check_anchors() +{ + /* Find mutually recursive with elements */ + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + if (!with_elem->is_recursive) + continue; + + table_map with_elem_dep= with_elem->derived_dep_map; + table_map with_elem_map= with_elem->get_elem_map(); + for (With_element *elem= with_elem; + elem != NULL; + elem= elem->next_elem) { - if (!tbl->with) - tbl->with= owner->find_table_def(tbl); - if (!tbl->with && tbl->select_lex) - tbl->with= tbl->select_lex->find_table_def_in_with_clauses(tbl); - if (tbl->with && tbl->with->owner== this->owner) - set_dependency_on(tbl->with); + if (!elem->is_recursive) + continue; + + if (elem == with_elem || + ((elem->derived_dep_map & with_elem_map) && + (with_elem_dep & elem->get_elem_map()))) + { + with_elem->mutually_recursive|= elem->get_elem_map(); + elem->mutually_recursive|= with_elem_map; + } } - st_select_lex_unit *inner_unit= sl->first_inner_unit(); - for (; inner_unit; inner_unit= inner_unit->next_unit()) - check_dependencies_in_unit(inner_unit); + + for (st_select_lex *sl= with_elem->spec->first_select(); + sl; + sl= sl->next_select()) + { + if (!(with_elem->mutually_recursive & sl->with_dep)) + { + with_elem->with_anchor= true; + break; + } + } + } + + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + if (!with_elem->is_recursive || with_elem->with_anchor) + continue; + + table_map anchored= 0; + for (With_element *elem= with_elem; + elem != NULL; + elem= elem->next_elem) + { + if (elem->mutually_recursive && elem->with_anchor) + anchored |= elem->get_elem_map(); + } + table_map non_anchored= with_elem->mutually_recursive & ~anchored; + with_elem->work_dep_map= non_anchored & with_elem->base_dep_map; } + + /*Building transitive clousure on work_dep_map*/ + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + table_map with_elem_map= with_elem->get_elem_map(); + for (With_element *elem= first_elem; elem != NULL; elem= elem->next_elem) + { + if (elem->work_dep_map & with_elem_map) + elem->work_dep_map|= with_elem->work_dep_map; + } + } + + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + if (with_elem->work_dep_map & with_elem->get_elem_map()) + { + my_error(ER_RECURSIVE_WITHOUT_ANCHORS, MYF(0), + with_elem->query_name->str); + return true; + } + } + + return false; } @@ -438,8 +558,8 @@ With_element::rename_columns_of_derived_unit(THD *thd, item->is_autogenerated_name= false; } } - - make_valid_column_names(thd, select->item_list); + else + make_valid_column_names(thd, select->item_list); unit->columns_are_renamed= true; @@ -486,6 +606,47 @@ bool With_element::prepare_unreferenced(THD *thd) } + +void With_clause::move_anchors_ahead() +{ + for (With_element *with_elem= first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + if (with_elem->is_recursive) + with_elem->move_anchors_ahead(); + } +} + + +void With_element::move_anchors_ahead() +{ + st_select_lex *next_sl; + st_select_lex *new_pos= spec->first_select(); + st_select_lex *last_sl; + new_pos->linkage= UNION_TYPE; + for (st_select_lex *sl= new_pos; sl; sl= next_sl) + { + next_sl= sl->next_select(); + if (is_anchor(sl)) + { + sl->move_node(new_pos); + new_pos= sl->next_select(); + } + last_sl= sl; + } + if (spec->union_distinct) + spec->union_distinct= last_sl; + first_recursive= new_pos; +} + + +bool With_element::is_anchor(st_select_lex *sel) +{ + return !(mutually_recursive & sel->with_dep); +} + + /** @brief Search for the definition of the given table referred in this select node @@ -540,7 +701,7 @@ With_element *st_select_lex::find_table_def_in_with_clauses(TABLE_LIST *table) bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) { with= with_elem; - if (!with_elem->is_referenced()) + if (!with_elem->is_referenced() || with_elem->is_recursive) derived= with_elem->spec; else { @@ -553,6 +714,102 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) } +bool TABLE_LIST::is_recursive_with_table() +{ + return with && with->is_recursive; +} + + +bool TABLE_LIST::is_with_table_recursive_reference() +{ + return (with_internal_reference_map && + (with->mutually_recursive & with_internal_reference_map)); +} + + + +bool st_select_lex::check_unrestricted_recursive() +{ + With_element *with_elem= get_with_element(); + if (!with_elem) + return false; + table_map unrestricted= 0; + table_map encountered= 0; + if (with_elem->check_unrestricted_recursive(this, + unrestricted, + encountered)) + return true; + with_elem->owner->unrestricted|= unrestricted; + return false; +} + + +bool With_element::check_unrestricted_recursive(st_select_lex *sel, + table_map &unrestricted, + table_map &encountered) +{ + List_iterator<TABLE_LIST> ti(sel->leaf_tables); + TABLE_LIST *tbl; + while ((tbl= ti++)) + { + if (tbl->get_unit() && !tbl->is_with_table()) + { + st_select_lex_unit *unit= tbl->get_unit(); + if (tbl->is_materialized_derived()) + { + table_map dep_map; + check_dependencies_in_unit(unit, dep_map); + if (dep_map & get_elem_map()) + { + my_error(ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED, + MYF(0), query_name->str); + return true; + } + } + if (check_unrestricted_recursive(unit->first_select(), + unrestricted, + encountered)) + return true; + if (!(tbl->is_recursive_with_table() && unit->with_element->owner == owner)) + continue; + With_element *with_elem= unit->with_element; + if (encountered & with_elem->get_elem_map()) + unrestricted|= with_elem->mutually_recursive; + else + encountered|= with_elem->get_elem_map(); + } + } + for (With_element *with_elem= sel->get_with_element()->owner->first_elem; + with_elem != NULL; + with_elem= with_elem->next_elem) + { + if (!with_elem->is_recursive && (unrestricted & with_elem->get_elem_map())) + continue; + if (encountered & with_elem->get_elem_map()) + { + uint cnt= 0; + table_map mutually_recursive= with_elem->mutually_recursive; + for (table_map map= mutually_recursive >> with_elem->number; + map != 0; + map>>= 1) + { + if (map & 1) + { + if (cnt) + { + unrestricted|= with_elem->mutually_recursive; + break; + } + else + cnt++; + } + } + } + } + return false; +} + + /** @brief Print this with clause @@ -602,3 +859,4 @@ void With_element::print(String *str, enum_query_type query_type) str->append(')'); } + |