1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Simplified the code that fills recursive tables.

This commit is contained in:
Igor Babaev
2016-06-25 21:38:40 -07:00
parent 0eec187153
commit 9606525666
7 changed files with 144 additions and 214 deletions

View File

@@ -248,22 +248,32 @@ bool With_clause::check_anchors()
if (!with_elem->is_recursive) if (!with_elem->is_recursive)
continue; continue;
table_map with_elem_dep= with_elem->derived_dep_map; if (!with_elem->next_mutually_recursive)
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) With_element *last_mutually_recursive= with_elem;
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 (!elem->is_recursive)
continue;
if (elem == with_elem || if (elem == with_elem ||
((elem->derived_dep_map & with_elem_map) && ((elem->derived_dep_map & with_elem_map) &&
(with_elem_dep & elem->get_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(); 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(); for (st_select_lex *sl= with_elem->spec->first_select();

View File

@@ -39,6 +39,7 @@ private:
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;
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
the queries that are in the scope of the element (including the queries that are in the scope of the element (including
@@ -88,16 +89,20 @@ public:
TABLE *result_table; 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_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), 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), result_table(NULL),
first_rec_table_to_update(NULL)
{} {}
bool check_dependencies_in_spec(THD *thd); bool check_dependencies_in_spec(THD *thd);
@@ -146,6 +151,9 @@ public:
table_map get_mutually_recursive() { return mutually_recursive; } 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; } void set_table(TABLE *tab) { table= tab; }
TABLE *get_table() { return table; } TABLE *get_table() { return table; }
@@ -166,22 +174,6 @@ public:
void reset_for_exec(); 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 cleanup_stabilized();
void set_as_stabilized(); void set_as_stabilized();
@@ -228,8 +220,6 @@ private:
table_map unrestricted; table_map unrestricted;
table_map with_prepared_anchor; table_map with_prepared_anchor;
table_map cleaned; table_map cleaned;
table_map driving_recursive;
table_map incr_ready;
table_map stabilized; table_map stabilized;
public: public:
@@ -241,7 +231,7 @@ public:
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), with_prepared_anchor(0), cleaned(0), unrestricted(0), with_prepared_anchor(0), cleaned(0),
driving_recursive(0), incr_ready(0), stabilized(0), stabilized(0),
with_recursive(recursive_fl) with_recursive(recursive_fl)
{ last_next= &first_elem; } { last_next= &first_elem; }
@@ -331,68 +321,11 @@ void With_element::reset_for_exec()
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();
owner->driving_recursive&= ~get_elem_map(); first_rec_table_to_update= NULL;
cleanup_incr_ready();
cleanup_stabilized(); 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 inline
void With_element::cleanup_stabilized() void With_element::cleanup_stabilized()
{ {

View File

@@ -663,7 +663,6 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->is_with_table_recursive_reference()) if (derived->is_with_table_recursive_reference())
{ {
unit->with_element->rec_result->rec_tables.push_back(derived->table); unit->with_element->rec_result->rec_tables.push_back(derived->table);
derived->table->is_rec_table= true;
} }
} }
DBUG_ASSERT(derived->table || res); 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 Execute subquery of a materialized derived table/view and fill the result
table. table.
@@ -944,6 +965,7 @@ bool mysql_derived_create(THD *thd, LEX *lex, TABLE_LIST *derived)
@return TRUE Error @return TRUE Error
*/ */
bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
{ {
DBUG_ENTER("mysql_derived_fill"); 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 derived_is_recursive= derived->is_recursive_with_table();
bool res= FALSE; 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 && if (unit->executed && !unit->uncacheable && !unit->describe &&
!derived_is_recursive) !derived_is_recursive)
DBUG_RETURN(FALSE); 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_LEX *first_select= unit->first_select();
select_union *derived_result= derived->derived_result; select_union *derived_result= derived->derived_result;
SELECT_LEX *save_current_select= lex->current_select; 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 // execute union without clean up
if (derived_is_recursive)
unit->with_element->set_result_table(derived->table);
res= unit->exec(); res= unit->exec();
} }
else else
@@ -995,15 +1012,13 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived)
derived_result, unit, first_select); derived_result, unit, first_select);
} }
if (!res) if (!res && !derived_is_recursive)
{ {
if (derived_result->flush()) if (derived_result->flush())
res= TRUE; res= TRUE;
unit->executed= TRUE; unit->executed= TRUE;
} }
if (res || if (res || (!lex->describe && !derived_is_recursive))
(!lex->describe &&
!(unit->with_element && unit->with_element->is_recursive)))
unit->cleanup(); unit->cleanup();
lex->current_select= save_current_select; lex->current_select= save_current_select;

View File

@@ -704,7 +704,7 @@ public:
bool prepare(THD *thd, select_result *result, ulong additional_options); bool prepare(THD *thd, select_result *result, ulong additional_options);
bool optimize(); bool optimize();
bool exec(); bool exec();
bool exec_recursive(); bool exec_recursive(bool is_driving_recursive);
bool cleanup(); bool cleanup();
inline void unclean() { cleaned= 0; } inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism(); void reinit_exec_mechanism();

View File

@@ -11606,11 +11606,7 @@ bool JOIN_TAB::preread_init()
/* Materialize derived table/view. */ /* Materialize derived table/view. */
if ((!derived->get_unit()->executed || if ((!derived->get_unit()->executed ||
(derived->is_recursive_with_table() && 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()))) &&
mysql_handle_single_derived(join->thd->lex, mysql_handle_single_derived(join->thd->lex,
derived, DT_CREATE | DT_FILL)) derived, DT_CREATE | DT_FILL))
return TRUE; 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(); flush_dups_table->sj_weedout_delete_rows();
} }
if ((!join_tab->preread_init_done || join_tab->table->is_rec_table) && if (!join_tab->preread_init_done && join_tab->preread_init())
join_tab->preread_init())
DBUG_RETURN(NESTED_LOOP_ERROR); DBUG_RETURN(NESTED_LOOP_ERROR);
join->return_tab= join_tab; join->return_tab= join_tab;
@@ -19195,8 +19190,7 @@ int join_init_read_record(JOIN_TAB *tab)
report_error(tab->table, error); report_error(tab->table, error);
return 1; return 1;
} }
if ((!tab->preread_init_done || tab->table->is_rec_table) && if (!tab->preread_init_done && tab->preread_init())
tab->preread_init())
return 1; return 1;
if (init_read_record(&tab->read_record, tab->join->thd, tab->table, if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
tab->select, tab->filesort_result, 1,1, FALSE)) 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 (!end_of_records)
{ {
#if 0
#endif
if (join->table_count && if (join->table_count &&
join->join_tab->is_using_loose_index_scan()) join->join_tab->is_using_loose_index_scan())
{ {

View File

@@ -244,7 +244,6 @@ select_union_recursive::create_result_table(THD *thd_arg,
if (rec_tables.push_back(rec_table)) if (rec_tables.push_back(rec_table))
return true; return true;
rec_table->is_rec_table= true;
return false; return false;
} }
@@ -918,9 +917,8 @@ bool st_select_lex_unit::exec()
bool first_execution= !executed; bool first_execution= !executed;
DBUG_ENTER("st_select_lex_unit::exec"); DBUG_ENTER("st_select_lex_unit::exec");
bool was_executed= executed; 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); DBUG_RETURN(FALSE);
executed= 1; executed= 1;
if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item) if (!(uncacheable & ~UNCACHEABLE_EXPLAIN) && item)
@@ -936,12 +934,6 @@ bool st_select_lex_unit::exec()
if (saved_error) if (saved_error)
DBUG_RETURN(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 (uncacheable || !item || !item->assigned() || describe)
{ {
if (!fake_select_lex && !(with_element && with_element->is_recursive)) if (!fake_select_lex && !(with_element && with_element->is_recursive))
@@ -1168,107 +1160,95 @@ err:
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 *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 *incr_table= with_element->rec_result->incr_table;
TABLE *result_table= with_element->result_table; st_select_lex *end= NULL;
ha_rows examined_rows= 0; bool is_unrestricted= with_element->is_unrestricted();
bool unrestricted= with_element->is_unrestricted();
bool with_anchor= with_element->with_anchor;
uint max_level= thd->variables.max_recursion_level;
List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables); List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables);
ha_rows examined_rows= 0;
bool was_executed= executed;
TABLE *rec_table; TABLE *rec_table;
DBUG_ENTER("st_select_lex_unit::exec_recursive"); DBUG_ENTER("st_select_lex_unit::exec_recursive");
do executed= 1;
create_explain_query_if_not_exists(thd->lex, thd->mem_root);
if (!was_executed)
save_union_explain(thd->lex->explain);
if ((saved_error= incr_table->file->ha_delete_all_rows()))
goto err;
if (is_driving_recursive)
{ {
st_select_lex *first_sl; With_element *with_elem= with_element;
st_select_lex *barrier; while ((with_elem= with_elem->get_next_mutually_recursive()) !=
if ((saved_error= incr_table->file->ha_delete_all_rows())) with_element)
goto err;
if (with_element->no_driving_recursive_is_set())
with_element->set_as_driving_recursive();
if (with_element->level == 0)
{ {
first_sl= first_select(); rec_table= with_elem->first_rec_table_to_update;
if (with_anchor) if (rec_table)
barrier= first_recursive_sel; rec_table->reginfo.join_tab->preread_init_done= false;
else
barrier= NULL;
} }
else
{
first_sl= first_recursive_sel;
barrier= NULL;
}
if (with_element->all_incr_are_ready())
with_element->cleanup_incr_ready();
for (st_select_lex *sl= first_sl ; sl != barrier; sl= sl->next_select())
{
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;
}
}
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= incr_table->insert_all_rows_into(thd, rec_table,
!unrestricted)))
goto err;
}
if (!with_element->is_driving_recursive())
break;
} while (!with_element->all_are_stabilized());
if (with_element->is_driving_recursive())
{
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();
} }
if (with_element->level == 0)
{
start= first_select();
if (with_element->with_anchor)
end= with_element->first_recursive;
}
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)
{
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;
}
}
thd->inc_examined_row_count(examined_rows);
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++))
{
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; thd->lex->current_select= lex_select_save;
err: err:
thd->lex->set_limit_rows_examined(); thd->lex->set_limit_rows_examined();
DBUG_RETURN(saved_error); DBUG_RETURN(saved_error);
} }

View File

@@ -1244,7 +1244,6 @@ public:
bool alias_name_used; /* true if table_name is alias */ bool alias_name_used; /* true if table_name is alias */
bool get_fields_in_item_tree; /* Signal to fix_field */ bool get_fields_in_item_tree; /* Signal to fix_field */
bool m_needs_reopen; bool m_needs_reopen;
bool is_rec_table;
private: private:
bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/ bool created; /* For tmp tables. TRUE <=> tmp table was actually created.*/
public: public:
@@ -2234,6 +2233,7 @@ struct TABLE_LIST
bool is_with_table(); bool is_with_table();
bool is_recursive_with_table(); bool is_recursive_with_table();
bool is_with_table_recursive_reference(); bool is_with_table_recursive_reference();
bool fill_recursive(THD *thd);
inline void set_view() inline void set_view()
{ {