Commit 96065256 authored by Igor Babaev's avatar Igor Babaev

Simplified the code that fills recursive tables.

parent 0eec1871
......@@ -248,22 +248,32 @@ bool With_clause::check_anchors()
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 (!with_elem->next_mutually_recursive)
{
if (!elem->is_recursive)
continue;
if (elem == with_elem ||
((elem->derived_dep_map & with_elem_map) &&
(with_elem_dep & elem->get_elem_map())))
{
With_element *last_mutually_recursive= with_elem;
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 (!elem->is_recursive)
continue;
if (elem == with_elem ||
((elem->derived_dep_map & with_elem_map) &&
(with_elem_dep & elem->get_elem_map())))
{
elem->next_mutually_recursive= with_elem;
last_mutually_recursive->next_mutually_recursive= elem;
last_mutually_recursive= elem;
with_elem->mutually_recursive|= elem->get_elem_map();
elem->mutually_recursive|= with_elem_map;
}
}
for (With_element *elem= with_elem->next_mutually_recursive;
elem != with_elem;
elem= elem->next_mutually_recursive)
elem->mutually_recursive= with_elem->mutually_recursive;
}
for (st_select_lex *sl= with_elem->spec->first_select();
......
......@@ -39,6 +39,7 @@ class With_element : public Sql_alloc
table_map work_dep_map; // dependency map used for work
/* Dependency map of with elements mutually recursive with this with element */
table_map mutually_recursive;
With_element *next_mutually_recursive;
/*
Total number of references to this element in the FROM lists of
the queries that are in the scope of the element (including
......@@ -87,17 +88,21 @@ class With_element : public Sql_alloc
select_union_recursive *rec_result;
TABLE *result_table;
TABLE *first_rec_table_to_update;
With_element(LEX_STRING *name,
List <LEX_STRING> list,
st_select_lex_unit *unit)
: next_elem(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),
references(0), table(NULL),
query_name(name), column_list(list), spec(unit),
is_recursive(false), with_anchor(false),
level(0), rec_result(NULL), result_table(NULL)
level(0), rec_result(NULL), result_table(NULL),
first_rec_table_to_update(NULL)
{}
bool check_dependencies_in_spec(THD *thd);
......@@ -146,6 +151,9 @@ class With_element : public Sql_alloc
table_map get_mutually_recursive() { return mutually_recursive; }
With_element *get_next_mutually_recursive()
{ return next_mutually_recursive; }
void set_table(TABLE *tab) { table= tab; }
TABLE *get_table() { return table; }
......@@ -166,22 +174,6 @@ class With_element : public Sql_alloc
void reset_for_exec();
bool no_driving_recursive_is_set();
void set_as_driving_recursive();
bool is_driving_recursive();
void cleanup_driving_recursive();
void cleanup_incr_ready();
void set_as_incr_ready();
bool is_incr_ready();
bool all_incr_are_ready();
void cleanup_stabilized();
void set_as_stabilized();
......@@ -228,8 +220,6 @@ class With_clause : public Sql_alloc
table_map unrestricted;
table_map with_prepared_anchor;
table_map cleaned;
table_map driving_recursive;
table_map incr_ready;
table_map stabilized;
public:
......@@ -241,7 +231,7 @@ class With_clause : public Sql_alloc
embedding_with_clause(emb_with_clause), next_with_clause(NULL),
dependencies_are_checked(false),
unrestricted(0), with_prepared_anchor(0), cleaned(0),
driving_recursive(0), incr_ready(0), stabilized(0),
stabilized(0),
with_recursive(recursive_fl)
{ last_next= &first_elem; }
......@@ -331,68 +321,11 @@ void With_element::reset_for_exec()
level= 0;
owner->with_prepared_anchor&= ~mutually_recursive;
owner->cleaned&= ~get_elem_map();
owner->driving_recursive&= ~get_elem_map();
cleanup_incr_ready();
first_rec_table_to_update= NULL;
cleanup_stabilized();
}
inline
bool With_element::no_driving_recursive_is_set()
{
return !(owner->driving_recursive & mutually_recursive);
}
inline
void With_element::set_as_driving_recursive()
{
owner->driving_recursive|= get_elem_map();
}
inline
bool With_element::is_driving_recursive()
{
return owner->driving_recursive & get_elem_map();
}
inline
void With_element::cleanup_driving_recursive()
{
owner->driving_recursive&= ~mutually_recursive;
}
inline
void With_element::cleanup_incr_ready()
{
owner->incr_ready&= ~mutually_recursive;
}
inline
void With_element::set_as_incr_ready()
{
owner->incr_ready|= get_elem_map();
}
inline
bool With_element::is_incr_ready()
{
return owner->incr_ready & get_elem_map();
}
inline
bool With_element::all_incr_are_ready()
{
return (owner->incr_ready & mutually_recursive) == mutually_recursive;
}
inline
void With_element::cleanup_stabilized()
{
......
......@@ -663,7 +663,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->is_with_table_recursive_reference())
{
unit->with_element->rec_result->rec_tables.push_back(derived->table);
derived->table->is_rec_table= true;
}
}
DBUG_ASSERT(derived->table || res);
......@@ -921,6 +920,28 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
}
bool TABLE_LIST::fill_recursive(THD *thd)
{
bool rc= false;
st_select_lex_unit *unit= get_unit();
if (is_with_table_recursive_reference())
rc= unit->exec_recursive(false);
else
{
while(!with->all_are_stabilized() && !rc)
{
rc= unit->exec_recursive(true);
}
if (!rc)
{
TABLE *src= with->rec_result->table;
rc =src->insert_all_rows_into(thd, table, true);
}
}
return rc;
}
/*
Execute subquery of a materialized derived table/view and fill the result
table.
......@@ -944,6 +965,7 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
@return TRUE Error
*/
bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
{
DBUG_ENTER("mysql_derived_fill");
......@@ -951,14 +973,6 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
bool derived_is_recursive= derived->is_recursive_with_table();
bool res= FALSE;
if (derived_is_recursive && derived->with->all_are_stabilized())
{
TABLE *src= unit->with_element->rec_result->table;
TABLE *dest= derived->table;
res= src->insert_all_rows_into(thd, dest, true);
DBUG_RETURN(res);
}
if (unit->executed && !unit->uncacheable && !unit->describe &&
!derived_is_recursive)
DBUG_RETURN(FALSE);
......@@ -967,11 +981,14 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
SELECT_LEX *first_select= unit->first_select();
select_union *derived_result= derived->derived_result;
SELECT_LEX *save_current_select= lex->current_select;
if (unit->is_union() || derived_is_recursive)
if (derived_is_recursive)
{
res= derived->fill_recursive(thd);
}
else if (unit->is_union())
{
// execute union without clean up
if (derived_is_recursive)
unit->with_element->set_result_table(derived->table);
res= unit->exec();
}
else
......@@ -995,15 +1012,13 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
derived_result, unit, first_select);
}
if (!res)
if (!res && !derived_is_recursive)
{
if (derived_result->flush())
res= TRUE;
unit->executed= TRUE;
}
if (res ||
(!lex->describe &&
!(unit->with_element && unit->with_element->is_recursive)))
if (res || (!lex->describe && !derived_is_recursive))
unit->cleanup();
lex->current_select= save_current_select;
......
......@@ -704,7 +704,7 @@ class st_select_lex_unit: public st_select_lex_node {
bool prepare(THD *thd, select_result *result, ulong additional_options);
bool optimize();
bool exec();
bool exec_recursive();
bool exec_recursive(bool is_driving_recursive);
bool cleanup();
inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism();
......
......@@ -11606,11 +11606,7 @@ bool JOIN_TAB::preread_init()
/* Materialize derived table/view. */
if ((!derived->get_unit()->executed ||
(derived->is_recursive_with_table() &&
(!derived->is_with_table_recursive_reference() ||
(!derived->with->is_driving_recursive() &&
!derived->with->is_incr_ready()) &&
!derived->with->all_are_stabilized()))) &&
derived->is_recursive_with_table()) &&
mysql_handle_single_derived(join->thd->lex,
derived, DT_CREATE | DT_FILL))
return TRUE;
......@@ -18241,8 +18237,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
flush_dups_table->sj_weedout_delete_rows();
}
if ((!join_tab->preread_init_done || join_tab->table->is_rec_table) &&
join_tab->preread_init())
if (!join_tab->preread_init_done && join_tab->preread_init())
DBUG_RETURN(NESTED_LOOP_ERROR);
join->return_tab= join_tab;
......@@ -19195,8 +19190,7 @@ int join_init_read_record(JOIN_TAB *tab)
report_error(tab->table, error);
return 1;
}
if ((!tab->preread_init_done || tab->table->is_rec_table) &&
tab->preread_init())
if (!tab->preread_init_done && tab->preread_init())
return 1;
if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select, tab->filesort_result, 1,1, FALSE))
......@@ -19429,8 +19423,6 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!end_of_records)
{
#if 0
#endif
if (join->table_count &&
join->join_tab->is_using_loose_index_scan())
{
......
......@@ -244,7 +244,6 @@ select_union_recursive::create_result_table(THD *thd_arg,
if (rec_tables.push_back(rec_table))
return true;
rec_table->is_rec_table= true;
return false;
}
......@@ -918,9 +917,8 @@ bool st_select_lex_unit::exec()
bool first_execution= !executed;
DBUG_ENTER("st_select_lex_unit::exec");
bool was_executed= executed;
bool is_recursive= with_element && with_element->is_recursive;
if (executed && !uncacheable && !describe && !is_recursive)
if (executed && !uncacheable && !describe)
DBUG_RETURN(FALSE);
executed= 1;
if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item)
......@@ -936,12 +934,6 @@ bool st_select_lex_unit::exec()
if (saved_error)
DBUG_RETURN(saved_error);
if (is_recursive && !describe)
{
saved_error= exec_recursive();
DBUG_RETURN(saved_error);
}
if (uncacheable || !item || !item->assigned() || describe)
{
if (!fake_select_lex && !(with_element && with_element->is_recursive))
......@@ -1168,107 +1160,95 @@ bool st_select_lex_unit::exec()
bool st_select_lex_unit::exec_recursive()
bool st_select_lex_unit::exec_recursive(bool is_driving_recursive)
{
st_select_lex *lex_select_save= thd->lex->current_select;
st_select_lex *first_recursive_sel= with_element->first_recursive;
st_select_lex *start= with_element->first_recursive;
TABLE *incr_table= with_element->rec_result->incr_table;
TABLE *result_table= with_element->result_table;
ha_rows examined_rows= 0;
bool unrestricted= with_element->is_unrestricted();
bool with_anchor= with_element->with_anchor;
uint max_level= thd->variables.max_recursion_level;
st_select_lex *end= NULL;
bool is_unrestricted= with_element->is_unrestricted();
List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables);
ha_rows examined_rows= 0;
bool was_executed= executed;
TABLE *rec_table;
DBUG_ENTER("st_select_lex_unit::exec_recursive");
do
{
st_select_lex *first_sl;
st_select_lex *barrier;
if ((saved_error= incr_table->file->ha_delete_all_rows()))
goto err;
executed= 1;
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
if (!was_executed)
save_union_explain(thd->lex->explain);
if (with_element->no_driving_recursive_is_set())
with_element->set_as_driving_recursive();
if ((saved_error= incr_table->file->ha_delete_all_rows()))
goto err;
if (with_element->level == 0)
{
first_sl= first_select();
if (with_anchor)
barrier= first_recursive_sel;
else
barrier= NULL;
}
else
if (is_driving_recursive)
{
With_element *with_elem= with_element;
while ((with_elem= with_elem->get_next_mutually_recursive()) !=
with_element)
{
first_sl= first_recursive_sel;
barrier= NULL;
rec_table= with_elem->first_rec_table_to_update;
if (rec_table)
rec_table->reginfo.join_tab->preread_init_done= false;
}
}
if (with_element->all_incr_are_ready())
with_element->cleanup_incr_ready();
if (with_element->level == 0)
{
start= first_select();
if (with_element->with_anchor)
end= with_element->first_recursive;
}
for (st_select_lex *sl= first_sl ; sl != barrier; sl= sl->next_select())
for (st_select_lex *sl= start ; sl != end; sl= sl->next_select())
{
thd->lex->current_select= sl;
sl->join->exec();
saved_error= sl->join->error;
if (!saved_error)
{
thd->lex->current_select= sl;
sl->join->exec();
saved_error= sl->join->error;
if (!saved_error)
{
examined_rows+= thd->get_examined_row_count();
thd->set_examined_row_count(0);
if (union_result->flush())
{
thd->lex->current_select= lex_select_save;
DBUG_RETURN(1);
}
}
if (saved_error)
{
thd->lex->current_select= lex_select_save;
goto err;
}
examined_rows+= thd->get_examined_row_count();
thd->set_examined_row_count(0);
if (union_result->flush())
{
thd->lex->current_select= lex_select_save;
DBUG_RETURN(1);
}
}
with_element->set_as_incr_ready();
incr_table->file->info(HA_STATUS_VARIABLE);
if (incr_table->file->stats.records == 0 ||
with_element->level + 1 == max_level)
with_element->set_as_stabilized();
else
with_element->level++;
li.rewind();
while ((rec_table= li++))
if (saved_error)
{
if ((saved_error= incr_table->insert_all_rows_into(thd, rec_table,
!unrestricted)))
goto err;
thd->lex->current_select= lex_select_save;
goto err;
}
if (!with_element->is_driving_recursive())
break;
}
} while (!with_element->all_are_stabilized());
thd->inc_examined_row_count(examined_rows);
if (with_element->is_driving_recursive())
incr_table->file->info(HA_STATUS_VARIABLE);
if (incr_table->file->stats.records == 0)
with_element->set_as_stabilized();
else
with_element->level++;
while ((rec_table= li++))
{
TABLE *table= with_element->rec_result->table;
if ((saved_error= table->insert_all_rows_into(thd,
result_table,
true)))
goto err;
with_element->cleanup_driving_recursive();
saved_error=
incr_table->insert_all_rows_into(thd, rec_table, !is_unrestricted);
if (!with_element->first_rec_table_to_update)
with_element->first_rec_table_to_update= rec_table;
if (with_element->level == 1)
rec_table->reginfo.join_tab->preread_init_done= true;
}
if (with_element->level == thd->variables.max_recursion_level)
with_element->set_as_stabilized();
thd->lex->current_select= lex_select_save;
err:
thd->lex->set_limit_rows_examined();
DBUG_RETURN(saved_error);
DBUG_RETURN(saved_error);
}
......
......@@ -1244,7 +1244,6 @@ struct TABLE
bool alias_name_used; /* true if table_name is alias */
bool get_fields_in_item_tree; /* Signal to fix_field */
bool m_needs_reopen;
bool is_rec_table;
private:
bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/
public:
......@@ -2234,6 +2233,7 @@ struct TABLE_LIST
bool is_with_table();
bool is_recursive_with_table();
bool is_with_table_recursive_reference();
bool fill_recursive(THD *thd);
inline void set_view()
{
......
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