diff options
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r-- | sql/sql_union.cc | 253 |
1 files changed, 246 insertions, 7 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 87b836f40d9..ac582c115d8 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -28,6 +28,8 @@ #include "sql_cursor.h" #include "sql_base.h" // fill_record #include "filesort.h" // filesort_free_buffers +#include "sql_view.h" +#include "sql_cte.h" bool mysql_union(THD *thd, LEX *lex, select_result *result, SELECT_LEX_UNIT *unit, ulong setup_tables_done_option) @@ -98,6 +100,26 @@ int select_union::send_data(List<Item> &values) return 0; } +int select_union_recursive::send_data(List<Item> &values) +{ + int rc= select_union::send_data(values); + + if (!write_err) + { + int err; + if ((err= incr_table->file->ha_write_tmp_row(table->record[0]))) + { + bool is_duplicate; + rc= create_internal_tmp_table_from_heap(thd, incr_table, + tmp_table_param.start_recinfo, + &tmp_table_param.recinfo, + err, 1, &is_duplicate); + } + } + + return rc; +} + bool select_union::send_eof() { @@ -171,6 +193,61 @@ select_union::create_result_table(THD *thd_arg, List<Item> *column_types, return FALSE; } +bool +select_union_recursive::create_result_table(THD *thd_arg, + List<Item> *column_types, + bool is_union_distinct, + ulonglong options, + const char *alias, + bool bit_fields_as_long, + bool create_table, + bool keep_row_order) +{ + if (select_union::create_result_table(thd_arg, column_types, + is_union_distinct, options, + alias, bit_fields_as_long, + create_table, keep_row_order)) + return true; + + if (! (incr_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, + (ORDER*) 0, false, 1, + options, HA_POS_ERROR, alias, + !create_table, keep_row_order))) + return true; + + incr_table->keys_in_use_for_query.clear_all(); + for (uint i=0; i < table->s->fields; i++) + incr_table->field[i]->flags &= ~PART_KEY_FLAG; + + if (create_table) + { + incr_table->file->extra(HA_EXTRA_WRITE_CACHE); + incr_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + } + + TABLE *rec_table= 0; + if (! (rec_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, + (ORDER*) 0, false, 1, + options, HA_POS_ERROR, alias, + !create_table, keep_row_order))) + return true; + + rec_table->keys_in_use_for_query.clear_all(); + for (uint i=0; i < table->s->fields; i++) + rec_table->field[i]->flags &= ~PART_KEY_FLAG; + + if (create_table) + { + rec_table->file->extra(HA_EXTRA_WRITE_CACHE); + rec_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + } + + if (rec_tables.push_back(rec_table)) + return true; + + return false; +} + /** Reset and empty the temporary table that stores the materialized query @@ -187,6 +264,29 @@ void select_union::cleanup() } +void select_union_recursive::cleanup() +{ + select_union::cleanup(); + free_tmp_table(thd, table); + + incr_table->file->extra(HA_EXTRA_RESET_STATE); + incr_table->file->ha_delete_all_rows(); + //free_io_cache(incr_table); + //filesort_free_buffers(incr_table,0); + free_tmp_table(thd, incr_table); + + List_iterator<TABLE> it(rec_tables); + TABLE *tab; + while ((tab= it++)) + { + tab->file->extra(HA_EXTRA_RESET_STATE); + tab->file->ha_delete_all_rows(); + //free_io_cache(tab); + //filesort_free_buffers(tab,0); + free_tmp_table(thd, tab); + } +} + /** Replace the current result with new_result and prepare it. @@ -332,11 +432,14 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg, } + + bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ulong additional_options) { SELECT_LEX *lex_select_save= thd_arg->lex->current_select; SELECT_LEX *sl, *first_sl= first_select(); + bool is_recursive= with_element && with_element->is_recursive; select_result *tmp_result; bool is_union_select; bool instantiate_tmp_table= false; @@ -404,8 +507,15 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } else { - if (!(tmp_result= union_result= - new (thd_arg->mem_root) select_union(thd_arg))) + if (!is_recursive) + union_result= new (thd_arg->mem_root) select_union(thd_arg); + else + { + with_element->rec_result= + new (thd_arg->mem_root) select_union_recursive(thd_arg); + union_result= with_element->rec_result; + } + if (!(tmp_result= union_result)) goto err; /* purecov: inspected */ instantiate_tmp_table= true; } @@ -414,7 +524,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, tmp_result= sel_result; sl->context.resolve_in_select_list= TRUE; - + for (;sl; sl= sl->next_select()) { bool can_skip_order_by; @@ -477,6 +587,13 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, types= first_sl->item_list; else if (sl == first_sl) { + if (is_recursive) + { + if (derived->with->rename_columns_of_derived_unit(thd, this)) + goto err; + if (check_duplicate_names(thd, sl->item_list, 0)) + goto err; + } types.empty(); List_iterator_fast<Item> it(sl->item_list); Item *item_tmp; @@ -489,6 +606,23 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (thd_arg->is_fatal_error) goto err; // out of memory + + if (is_recursive) + { + + ulonglong create_options; + create_options= (first_sl->options | thd_arg->variables.option_bits | + TMP_TABLE_ALL_COLUMNS); + if (union_result->create_result_table(thd, &types, + MY_TEST(union_distinct), + create_options, "", false, + instantiate_tmp_table, false)) + goto err; + if (!derived->table) + derived->table= derived->derived_result->table= + with_element->rec_result->rec_tables.head(); + with_element->mark_as_with_prepared_anchor(); + } } else { @@ -507,6 +641,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, DBUG_RETURN(TRUE); } } + if (with_element && !with_element->is_anchor(sl)) + { + sl->uncacheable|= UNCACHEABLE_UNITED; + } } /* @@ -580,9 +718,11 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (global_parameters()->ftfunc_list->elements) create_options= create_options | TMP_TABLE_FORCE_MYISAM; - if (union_result->create_result_table(thd, &types, MY_TEST(union_distinct), - create_options, "", false, - instantiate_tmp_table)) + + if (!is_recursive && + union_result->create_result_table(thd, &types, MY_TEST(union_distinct), + create_options, "", false, + instantiate_tmp_table, false)) goto err; if (fake_select_lex && !fake_select_lex->first_cond_optimization) { @@ -784,6 +924,12 @@ bool st_select_lex_unit::exec() if (saved_error) DBUG_RETURN(saved_error); + if (with_element && with_element->is_recursive && !describe) + { + saved_error= exec_recursive(); + DBUG_RETURN(saved_error); + } + if (uncacheable || !item || !item->assigned() || describe) { if (!fake_select_lex) @@ -1009,6 +1155,89 @@ err: } + +bool st_select_lex_unit::exec_recursive() +{ + st_select_lex *lex_select_save= thd->lex->current_select; + st_select_lex *first_recursive_sel= with_element->first_recursive; + TABLE *incr_table= with_element->rec_result->incr_table; + TABLE *result_table= with_element->result_table; + ha_rows last_union_records= 0; + ha_rows examined_rows= 0; + bool unrestricted= with_element->is_unrestricted(); + bool is_stabilized= false; + DBUG_ENTER("st_select_lex_unit::exec_recursive"); + bool with_anchor= with_element->with_anchor; + st_select_lex *first_sl= first_select(); + st_select_lex *barrier= with_anchor ? first_recursive_sel : NULL; + List_iterator_fast<TABLE> li(with_element->rec_result->rec_tables); + TABLE *rec_table; + + do + { + if ((saved_error= incr_table->file->ha_delete_all_rows())) + goto err; + + 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; + } + } + + if (with_element->level == 0) + { + first_sl= first_recursive_sel; + barrier= NULL; + } + + table->file->info(HA_STATUS_VARIABLE); + if (table->file->stats.records == last_union_records) + { + is_stabilized= true; + } + else + { + last_union_records= table->file->stats.records; + with_element->level++; + } + li.rewind(); + while ((rec_table= li++)) + { + if ((saved_error= incr_table->insert_all_rows_into(thd, rec_table, + !unrestricted))) + goto err; + } + } while (!is_stabilized); + + if ((saved_error= table->insert_all_rows_into(thd, + result_table, + true))) + goto err; + + thd->lex->current_select= lex_select_save; +err: + thd->lex->set_limit_rows_examined(); + DBUG_RETURN(saved_error); + +} + + bool st_select_lex_unit::cleanup() { int error= 0; @@ -1023,6 +1252,13 @@ bool st_select_lex_unit::cleanup() for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) 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) { error|= fake_select_lex->cleanup(); @@ -1046,7 +1282,10 @@ bool st_select_lex_unit::cleanup() } } - if (union_result) + if (with_element && with_element->is_recursive) + with_element->mark_as_cleaned(); + + if (union_result && !(with_element->is_recursive)) { delete union_result; union_result=0; // Safety |