Commit c8f85bf2 authored by Igor Babaev's avatar Igor Babaev

mdev-9864: cleanup, re-factoring.

Added comments.
parent f33c3524
...@@ -128,6 +128,11 @@ class Item_subselect :public Item_result_field, ...@@ -128,6 +128,11 @@ class Item_subselect :public Item_result_field,
/* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */ /* TRUE <=> The underlying SELECT is correlated w.r.t some ancestor select */
bool is_correlated; bool is_correlated;
/*
TRUE <=> the subquery contains a recursive reference in the FROM list
of one of its selects. In this case some of subquery optimization
strategies cannot be applied for the subquery;
*/
bool with_recursive_reference; bool with_recursive_reference;
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
......
...@@ -7157,7 +7157,7 @@ ER_RECURSIVE_WITHOUT_ANCHORS ...@@ -7157,7 +7157,7 @@ ER_RECURSIVE_WITHOUT_ANCHORS
ER_UNACCEPTABLE_MUTUAL_RECURSION ER_UNACCEPTABLE_MUTUAL_RECURSION
eng "Unacceptable mutual recursion with anchored table '%s'" eng "Unacceptable mutual recursion with anchored table '%s'"
ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED ER_REF_TO_RECURSIVE_WITH_TABLE_IN_DERIVED
eng "Reference to recursive WITH table '%s' in materiazed derived" eng "Reference to recursive WITH table '%s' in materialized derived"
ER_NOT_STANDARDS_COMPLIANT_RECURSIVE ER_NOT_STANDARDS_COMPLIANT_RECURSIVE
eng "Restrictions imposed on recursive definitions are violated for table '%s'" eng "Restrictions imposed on recursive definitions are violated for table '%s'"
# #
......
...@@ -4682,10 +4682,12 @@ class select_union_recursive :public select_union ...@@ -4682,10 +4682,12 @@ class select_union_recursive :public select_union
{ {
public: public:
TABLE *incr_table; TABLE *incr_table;
TABLE *first_rec_table_to_update;
List<TABLE> rec_tables; List<TABLE> rec_tables;
select_union_recursive(THD *thd_arg): select_union_recursive(THD *thd_arg):
select_union(thd_arg), incr_table(0) {}; select_union(thd_arg),
incr_table(0), first_rec_table_to_update(0) {};
int send_data(List<Item> &items); int send_data(List<Item> &items);
bool create_result_table(THD *thd, List<Item> *column_types, bool create_result_table(THD *thd, List<Item> *column_types,
......
This diff is collapsed.
...@@ -21,7 +21,7 @@ class With_element : public Sql_alloc ...@@ -21,7 +21,7 @@ class With_element : public Sql_alloc
{ {
private: private:
With_clause *owner; // with clause this object belongs to With_clause *owner; // with clause this object belongs to
With_element *next_elem; // next element in the with clause With_element *next; // next element in the with clause
uint number; // number of the element in the with clause (starting from 0) uint number; // number of the element in the with clause (starting from 0)
table_map elem_map; // The map where with only one 1 set in this->number table_map elem_map; // The map where with only one 1 set in this->number
/* /*
...@@ -35,11 +35,23 @@ class With_element : public Sql_alloc ...@@ -35,11 +35,23 @@ class With_element : public Sql_alloc
The map derived_dep_map has 1 in i-th position if this with element depends The map derived_dep_map has 1 in i-th position if this with element depends
directly or indirectly from the i-th with element. directly or indirectly from the i-th with element.
*/ */
table_map derived_dep_map; table_map derived_dep_map;
/*
The map sq_dep_map has 1 in i-th position if there is a reference to this
with element somewhere in subqueries of the specifications of the tables
defined in the with clause containing this element;
*/
table_map sq_dep_map; table_map sq_dep_map;
table_map work_dep_map; // dependency map used for work table_map work_dep_map; // dependency map used for work
/* Dependency map of with elements mutually recursive with this with element */ /* Dependency map of with elements mutually recursive with this with element */
table_map mutually_recursive; table_map mutually_recursive;
/*
The next with element from the circular chain of the with elements
mutually recursive with this with element.
(If This element is simply recursive than next_mutually_recursive contains
the pointer to itself. If it's not recursive than next_mutually_recursive
is set to NULL.)
*/
With_element *next_mutually_recursive; With_element *next_mutually_recursive;
/* /*
Total number of references to this element in the FROM lists of Total number of references to this element in the FROM lists of
...@@ -56,8 +68,6 @@ class With_element : public Sql_alloc ...@@ -56,8 +68,6 @@ class With_element : public Sql_alloc
/* Return the map where 1 is set only in the position for this element */ /* Return the map where 1 is set only in the position for this element */
table_map get_elem_map() { return 1 << number; } table_map get_elem_map() { return 1 << number; }
TABLE *table;
public: public:
/* /*
The name of the table introduced by this with elememt. The name The name of the table introduced by this with elememt. The name
...@@ -79,34 +89,48 @@ class With_element : public Sql_alloc ...@@ -79,34 +89,48 @@ class With_element : public Sql_alloc
*/ */
bool is_recursive; bool is_recursive;
/*
Any non-recursive select in the specification of a recursive
with element is a called anchor. In the case mutually recursive
elements the specification of some them may be without any anchor.
Yet at least one of them must contain an anchor.
All anchors of any recursivespecification are moved ahead before
the prepare stage.
*/
/* Set to true if this is a recursive element with an anchor */
bool with_anchor; bool with_anchor;
/*
Set to the first recursive select of the unit specifying the element
after all anchor have been moved to the head of the unit.
*/
st_select_lex *first_recursive; st_select_lex *first_recursive;
/* The number of the last performed iteration for recursive table */ /*
The number of the last performed iteration for recursive table
(the number of the initial non-recursive step is 0, the number
of the first iteration is 1).
*/
uint level; uint level;
/*
The pointer to the object used to materialize this with element
if it's recursive. This object is built at the end of prepare
stage and is used at the execution stage.
*/
select_union_recursive *rec_result; select_union_recursive *rec_result;
TABLE *result_table;
TABLE *first_rec_table_to_update;
With_element(LEX_STRING *name, With_element(LEX_STRING *name,
List <LEX_STRING> list, List <LEX_STRING> list,
st_select_lex_unit *unit) st_select_lex_unit *unit)
: next_elem(NULL), base_dep_map(0), derived_dep_map(0), : next(NULL), base_dep_map(0), derived_dep_map(0),
sq_dep_map(0), work_dep_map(0), mutually_recursive(0), sq_dep_map(0), work_dep_map(0), mutually_recursive(0),
next_mutually_recursive(NULL), next_mutually_recursive(NULL), references(0),
references(0), table(NULL),
query_name(name), column_list(list), spec(unit), query_name(name), column_list(list), spec(unit),
is_recursive(false), with_anchor(false), is_recursive(false), with_anchor(false),
level(0), rec_result(NULL), result_table(NULL), level(0), rec_result(NULL)
first_rec_table_to_update(NULL)
{} {}
bool check_dependencies_in_spec(THD *thd); bool check_dependencies_in_spec();
void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt, void check_dependencies_in_select(st_select_lex *sl, st_unit_ctxt_elem *ctxt,
bool in_subq, table_map *dep_map); bool in_subq, table_map *dep_map);
...@@ -155,10 +179,6 @@ class With_element : public Sql_alloc ...@@ -155,10 +179,6 @@ class With_element : public Sql_alloc
With_element *get_next_mutually_recursive() With_element *get_next_mutually_recursive()
{ return next_mutually_recursive; } { return next_mutually_recursive; }
void set_table(TABLE *tab) { table= tab; }
TABLE *get_table() { return table; }
bool is_anchor(st_select_lex *sel); bool is_anchor(st_select_lex *sel);
void move_anchors_ahead(); void move_anchors_ahead();
...@@ -173,7 +193,7 @@ class With_element : public Sql_alloc ...@@ -173,7 +193,7 @@ class With_element : public Sql_alloc
void mark_as_cleaned(); void mark_as_cleaned();
void reset_for_exec(); void reset_recursive_for_exec();
void cleanup_stabilized(); void cleanup_stabilized();
...@@ -183,8 +203,6 @@ class With_element : public Sql_alloc ...@@ -183,8 +203,6 @@ class With_element : public Sql_alloc
bool all_are_stabilized(); bool all_are_stabilized();
void set_result_table(TABLE *tab) { result_table= tab; }
bool instantiate_tmp_tables(); bool instantiate_tmp_tables();
void prepare_for_next_iteration(); void prepare_for_next_iteration();
...@@ -206,9 +224,9 @@ class With_clause : public Sql_alloc ...@@ -206,9 +224,9 @@ class With_clause : public Sql_alloc
{ {
private: private:
st_select_lex_unit *owner; // the unit this with clause attached to st_select_lex_unit *owner; // the unit this with clause attached to
With_element *first_elem; // the first definition in this with clause
With_element **last_next; // here is set the link for the next added element /* The list of all with elements from this with clause */
uint elements; // number of the elements/defintions in this with clauses SQL_I_List<With_element> with_list;
/* /*
The with clause immediately containing this with clause if there is any, The with clause immediately containing this with clause if there is any,
otherwise NULL. Now used only at parsing. otherwise NULL. Now used only at parsing.
...@@ -222,9 +240,22 @@ class With_clause : public Sql_alloc ...@@ -222,9 +240,22 @@ class With_clause : public Sql_alloc
/* Set to true if dependencies between with elements have been checked */ /* Set to true if dependencies between with elements have been checked */
bool dependencies_are_checked; bool dependencies_are_checked;
/*
The bitmap of all recursive with elements whose specifications
are not complied with restrictions imposed by the SQL standards
on recursive specifications.
*/
table_map unrestricted; table_map unrestricted;
/*
The bitmap of all recursive with elements whose anchors
has been already prepared.
*/
table_map with_prepared_anchor; table_map with_prepared_anchor;
table_map cleaned; table_map cleaned;
/*
The bitmap of all recursive with elements that
has been already materialized
*/
table_map stabilized; table_map stabilized;
public: public:
...@@ -232,23 +263,20 @@ class With_clause : public Sql_alloc ...@@ -232,23 +263,20 @@ class With_clause : public Sql_alloc
bool with_recursive; bool with_recursive;
With_clause(bool recursive_fl, With_clause *emb_with_clause) With_clause(bool recursive_fl, With_clause *emb_with_clause)
: owner(NULL), first_elem(NULL), elements(0), : owner(NULL),
embedding_with_clause(emb_with_clause), next_with_clause(NULL), embedding_with_clause(emb_with_clause), next_with_clause(NULL),
dependencies_are_checked(false), dependencies_are_checked(false), unrestricted(0),
unrestricted(0), with_prepared_anchor(0), cleaned(0), with_prepared_anchor(0), cleaned(0), stabilized(0),
stabilized(0),
with_recursive(recursive_fl) with_recursive(recursive_fl)
{ last_next= &first_elem; } { }
/* Add a new element to the current with clause */ /* Add a new element to the current with clause */
bool add_with_element(With_element *elem) bool add_with_element(With_element *elem)
{ {
elem->owner= this; elem->owner= this;
elem->number= elements; elem->number= with_list.elements;
elem->spec->with_element= elem; elem->spec->with_element= elem;
*last_next= elem; with_list.link_in_list(elem, &elem->next);
last_next= &elem->next_elem;
elements++;
return false; return false;
} }
...@@ -263,7 +291,7 @@ class With_clause : public Sql_alloc ...@@ -263,7 +291,7 @@ class With_clause : public Sql_alloc
With_clause *pop() { return embedding_with_clause; } With_clause *pop() { return embedding_with_clause; }
bool check_dependencies(THD *thd); bool check_dependencies();
bool check_anchors(); bool check_anchors();
...@@ -283,7 +311,7 @@ class With_clause : public Sql_alloc ...@@ -283,7 +311,7 @@ class With_clause : public Sql_alloc
friend friend
bool bool
check_dependencies_in_with_clauses(THD *thd, With_clause *with_clauses_list); check_dependencies_in_with_clauses(With_clause *with_clauses_list);
}; };
inline inline
...@@ -321,16 +349,18 @@ void With_element::mark_as_cleaned() ...@@ -321,16 +349,18 @@ void With_element::mark_as_cleaned()
inline inline
void With_element::reset_for_exec() void With_element::reset_recursive_for_exec()
{ {
DBUG_ASSERT(is_recursive);
level= 0; level= 0;
owner->with_prepared_anchor&= ~mutually_recursive; owner->with_prepared_anchor&= ~mutually_recursive;
owner->cleaned&= ~get_elem_map(); owner->cleaned&= ~get_elem_map();
first_rec_table_to_update= NULL;
cleanup_stabilized(); cleanup_stabilized();
rec_result->first_rec_table_to_update= 0;
} }
inline inline
void With_element::cleanup_stabilized() void With_element::cleanup_stabilized()
{ {
...@@ -365,7 +395,7 @@ void With_element::prepare_for_next_iteration() ...@@ -365,7 +395,7 @@ void With_element::prepare_for_next_iteration()
With_element *with_elem= this; With_element *with_elem= this;
while ((with_elem= with_elem->get_next_mutually_recursive()) != this) while ((with_elem= with_elem->get_next_mutually_recursive()) != this)
{ {
TABLE *rec_table= with_elem->first_rec_table_to_update; TABLE *rec_table= with_elem->rec_result->first_rec_table_to_update;
if (rec_table) if (rec_table)
rec_table->reginfo.join_tab->preread_init_done= false; rec_table->reginfo.join_tab->preread_init_done= false;
} }
......
...@@ -1109,7 +1109,7 @@ class st_select_lex: public st_select_lex_node ...@@ -1109,7 +1109,7 @@ class st_select_lex: public st_select_lex_node
} }
With_element *find_table_def_in_with_clauses(TABLE_LIST *table); With_element *find_table_def_in_with_clauses(TABLE_LIST *table);
bool check_unrestricted_recursive(bool only_standards_compliant); bool check_unrestricted_recursive(bool only_standards_compliant);
void check_subqueries_with_recursive_references(); bool check_subqueries_with_recursive_references();
List<Window_spec> window_specs; List<Window_spec> window_specs;
void prepare_add_window_spec(THD *thd); void prepare_add_window_spec(THD *thd);
...@@ -2475,7 +2475,7 @@ struct LEX: public Query_tables_list ...@@ -2475,7 +2475,7 @@ struct LEX: public Query_tables_list
SELECT_LEX *all_selects_list; SELECT_LEX *all_selects_list;
/* current with clause in parsing if any, otherwise 0*/ /* current with clause in parsing if any, otherwise 0*/
With_clause *curr_with_clause; With_clause *curr_with_clause;
/* pointer to the first with clause in the current statemant */ /* pointer to the first with clause in the current statement */
With_clause *with_clauses_list; With_clause *with_clauses_list;
/* /*
(*with_clauses_list_last_next) contains a pointer to the last (*with_clauses_list_last_next) contains a pointer to the last
......
...@@ -6233,7 +6233,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) ...@@ -6233,7 +6233,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
new (thd->mem_root) Item_int(thd, new (thd->mem_root) Item_int(thd,
(ulonglong) thd->variables.select_limit); (ulonglong) thd->variables.select_limit);
} }
if (check_dependencies_in_with_clauses(thd, lex->with_clauses_list)) if (check_dependencies_in_with_clauses(lex->with_clauses_list))
return 1; return 1;
if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0)))
......
...@@ -1509,7 +1509,7 @@ static int mysql_test_select(Prepared_statement *stmt, ...@@ -1509,7 +1509,7 @@ static int mysql_test_select(Prepared_statement *stmt,
lex->select_lex.context.resolve_in_select_list= TRUE; lex->select_lex.context.resolve_in_select_list= TRUE;
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (check_dependencies_in_with_clauses(thd,lex->with_clauses_list)) if (check_dependencies_in_with_clauses(lex->with_clauses_list))
goto error; goto error;
if (tables) if (tables)
{ {
......
...@@ -1231,8 +1231,8 @@ bool st_select_lex_unit::exec_recursive() ...@@ -1231,8 +1231,8 @@ bool st_select_lex_unit::exec_recursive()
{ {
saved_error= saved_error=
incr_table->insert_all_rows_into(thd, rec_table, !is_unrestricted); incr_table->insert_all_rows_into(thd, rec_table, !is_unrestricted);
if (!with_element->first_rec_table_to_update) if (!with_element->rec_result->first_rec_table_to_update)
with_element->first_rec_table_to_update= rec_table; with_element->rec_result->first_rec_table_to_update= rec_table;
if (with_element->level == 1) if (with_element->level == 1)
rec_table->reginfo.join_tab->preread_init_done= true; rec_table->reginfo.join_tab->preread_init_done= true;
} }
...@@ -1257,14 +1257,7 @@ bool st_select_lex_unit::cleanup() ...@@ -1257,14 +1257,7 @@ bool st_select_lex_unit::cleanup()
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
error|= sl->cleanup(); error|= sl->cleanup();
if (union_result && with_element && with_element->is_recursive)
{
((select_union_recursive *) union_result)->cleanup();
delete union_result;
union_result= 0;
}
if (fake_select_lex) if (fake_select_lex)
{ {
error|= fake_select_lex->cleanup(); error|= fake_select_lex->cleanup();
...@@ -1289,15 +1282,25 @@ bool st_select_lex_unit::cleanup() ...@@ -1289,15 +1282,25 @@ bool st_select_lex_unit::cleanup()
} }
if (with_element && with_element->is_recursive) if (with_element && with_element->is_recursive)
{
if (union_result )
{
((select_union_recursive *) union_result)->cleanup();
delete union_result;
union_result= 0;
}
with_element->mark_as_cleaned(); with_element->mark_as_cleaned();
}
if (union_result && !(with_element &&with_element->is_recursive)) else
{ {
delete union_result; if (union_result)
union_result=0; // Safety {
if (table) delete union_result;
free_tmp_table(thd, table); union_result=0; // Safety
table= 0; // Safety if (table)
free_tmp_table(thd, table);
table= 0; // Safety
}
} }
DBUG_RETURN(error); DBUG_RETURN(error);
...@@ -1325,7 +1328,7 @@ void st_select_lex_unit::reinit_exec_mechanism() ...@@ -1325,7 +1328,7 @@ void st_select_lex_unit::reinit_exec_mechanism()
} }
#endif #endif
if (with_element && with_element->is_recursive) if (with_element && with_element->is_recursive)
with_element->reset_for_exec(); with_element->reset_recursive_for_exec();
} }
......
...@@ -430,7 +430,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -430,7 +430,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local); lex->link_first_table_back(view, link_to_local);
view->open_type= OT_BASE_ONLY; view->open_type= OT_BASE_ONLY;
if (check_dependencies_in_with_clauses(thd, lex->with_clauses_list)) if (check_dependencies_in_with_clauses(lex->with_clauses_list))
{ {
res= TRUE; res= TRUE;
goto err; goto err;
...@@ -1390,7 +1390,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, ...@@ -1390,7 +1390,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
TABLE_LIST *tbl; TABLE_LIST *tbl;
Security_context *security_ctx= 0; Security_context *security_ctx= 0;
if (check_dependencies_in_with_clauses(thd, thd->lex->with_clauses_list)) if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list))
goto err; goto err;
/* /*
......
...@@ -1857,8 +1857,9 @@ struct TABLE_LIST ...@@ -1857,8 +1857,9 @@ struct TABLE_LIST
derived tables. Use TABLE_LIST::is_anonymous_derived_table(). derived tables. Use TABLE_LIST::is_anonymous_derived_table().
*/ */
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
With_element *with; /* With element of with_table */ With_element *with; /* With element defining this table (if any) */
table_map with_internal_reference_map; /* Bitmap of the defining with element */
table_map with_internal_reference_map;
bool block_handle_derived; bool block_handle_derived;
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */ ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex; st_select_lex *schema_select_lex;
......
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