mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Simplified the code that fills recursive tables.
This commit is contained in:
@@ -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;
|
||||
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())))
|
||||
{
|
||||
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 @@ private:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
|
||||
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 @@ private:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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())
|
||||
{
|
||||
|
168
sql/sql_union.cc
168
sql/sql_union.cc
@@ -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 @@ 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 *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
|
||||
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;
|
||||
st_select_lex *barrier;
|
||||
if ((saved_error= incr_table->file->ha_delete_all_rows()))
|
||||
goto err;
|
||||
|
||||
if (with_element->no_driving_recursive_is_set())
|
||||
with_element->set_as_driving_recursive();
|
||||
|
||||
if (with_element->level == 0)
|
||||
With_element *with_elem= with_element;
|
||||
while ((with_elem= with_elem->get_next_mutually_recursive()) !=
|
||||
with_element)
|
||||
{
|
||||
first_sl= first_select();
|
||||
if (with_anchor)
|
||||
barrier= first_recursive_sel;
|
||||
else
|
||||
barrier= NULL;
|
||||
rec_table= with_elem->first_rec_table_to_update;
|
||||
if (rec_table)
|
||||
rec_table->reginfo.join_tab->preread_init_done= false;
|
||||
}
|
||||
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;
|
||||
err:
|
||||
thd->lex->set_limit_rows_examined();
|
||||
DBUG_RETURN(saved_error);
|
||||
|
||||
DBUG_RETURN(saved_error);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1244,7 +1244,6 @@ public:
|
||||
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()
|
||||
{
|
||||
|
Reference in New Issue
Block a user