diff options
Diffstat (limited to 'sql/sql_union.cc')
-rw-r--r-- | sql/sql_union.cc | 202 |
1 files changed, 122 insertions, 80 deletions
diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 0149c2848c2..a1963c33a42 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -36,7 +36,7 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result, { DBUG_ENTER("mysql_union"); bool res; - if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | + if (!(res= unit->prepare(unit->derived, result, SELECT_NO_UNLOCK | setup_tables_done_option))) res= unit->exec(); res|= unit->cleanup(); @@ -126,7 +126,7 @@ int select_unit::send_data(List<Item> &values) } else fill_record(thd, table, table->field, values, TRUE, FALSE); - if (thd->is_error()) + if (unlikely(thd->is_error())) { rc= 1; goto end; @@ -146,7 +146,8 @@ int select_unit::send_data(List<Item> &values) { case UNION_TYPE: { - if ((write_err= table->file->ha_write_tmp_row(table->record[0]))) + if (unlikely((write_err= + table->file->ha_write_tmp_row(table->record[0])))) { if (write_err == HA_ERR_FOUND_DUPP_KEY) { @@ -235,7 +236,7 @@ int select_unit::send_data(List<Item> &values) rc= 0; end: - if (not_reported_error) + if (unlikely(not_reported_error)) { DBUG_ASSERT(rc); table->file->print_error(not_reported_error, MYF(0)); @@ -267,32 +268,26 @@ bool select_unit::send_eof() handler *file= table->file; int error; - if (file->ha_rnd_init_with_error(1)) + if (unlikely(file->ha_rnd_init_with_error(1))) return 1; do { - error= file->ha_rnd_next(table->record[0]); - if (error) + if (unlikely(error= file->ha_rnd_next(table->record[0]))) { if (error == HA_ERR_END_OF_FILE) { error= 0; break; } - if (unlikely(error == HA_ERR_RECORD_DELETED)) - { - error= 0; - continue; - } break; } if (table->field[0]->val_int() != curr_step) error= file->ha_delete_tmp_row(table->record[0]); - } while (!error); + } while (likely(!error)); file->ha_rnd_end(); - if (error) + if (unlikely(error)) table->file->print_error(error, MYF(0)); return(MY_TEST(error)); @@ -325,7 +320,7 @@ int select_union_recursive::send_data(List<Item> &values) bool select_unit::flush() { int error; - if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) + if (unlikely((error=table->file->extra(HA_EXTRA_NO_CACHE)))) { table->file->print_error(error, MYF(0)); return 1; @@ -413,19 +408,13 @@ select_union_recursive::create_result_table(THD *thd_arg, if (! (incr_table= create_tmp_table(thd_arg, &tmp_table_param, *column_types, (ORDER*) 0, false, 1, options, HA_POS_ERROR, &empty_clex_str, - !create_table, keep_row_order))) + true, 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, @@ -469,8 +458,11 @@ void select_union_recursive::cleanup() if (incr_table) { - incr_table->file->extra(HA_EXTRA_RESET_STATE); - incr_table->file->ha_delete_all_rows(); + if (incr_table->is_created()) + { + incr_table->file->extra(HA_EXTRA_RESET_STATE); + incr_table->file->ha_delete_all_rows(); + } free_tmp_table(thd, incr_table); } @@ -507,14 +499,14 @@ void select_union_recursive::cleanup() bool select_union_direct::change_result(select_result *new_result) { result= new_result; - return (result->prepare(unit->types, unit) || result->prepare2()); + return (result->prepare(unit->types, unit) || result->prepare2(NULL)); } bool select_union_direct::postponed_prepare(List<Item> &types) { if (result != NULL) - return (result->prepare(types, unit) || result->prepare2()); + return (result->prepare(types, unit) || result->prepare2(NULL)); else return false; } @@ -555,7 +547,7 @@ int select_union_direct::send_data(List<Item> &items) send_records++; fill_record(thd, table, table->field, items, true, false); - if (thd->is_error()) + if (unlikely(thd->is_error())) return true; /* purecov: inspected */ return result->send_data(unit->item_list); @@ -678,7 +670,7 @@ bool st_select_lex_unit::prepare_join(THD *thd_arg, SELECT_LEX *sl, sl->with_wild= 0; last_procedure= join->procedure; - if (saved_error || (saved_error= thd_arg->is_fatal_error)) + if (unlikely(saved_error || (saved_error= thd_arg->is_fatal_error))) DBUG_RETURN(true); /* Remove all references from the select_lex_units to the subqueries that @@ -796,29 +788,40 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg, join_union_type_attributes(thd_arg, holders, count)) DBUG_RETURN(true); + bool is_recursive= with_element && with_element->is_recursive; types.empty(); List_iterator_fast<Item> it(first_sl->item_list); Item *item_tmp; for (uint pos= 0; (item_tmp= it++); pos++) { + /* + SQL standard requires forced nullability only for + recursive columns. However type aggregation in our + implementation so far does not differentiate between + recursive and non-recursive columns of a recursive CTE. + TODO: this should be fixed. + */ + bool pos_maybe_null= is_recursive ? true : holders[pos].get_maybe_null(); + /* Error's in 'new' will be detected after loop */ types.push_back(new (thd_arg->mem_root) Item_type_holder(thd_arg, item_tmp, holders[pos].type_handler(), &holders[pos]/*Type_all_attributes*/, - holders[pos].get_maybe_null())); + pos_maybe_null)); } - if (thd_arg->is_fatal_error) + if (unlikely(thd_arg->is_fatal_error)) DBUG_RETURN(true); // out of memory DBUG_RETURN(false); } -bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, +bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg, + select_result *sel_result, ulong additional_options) { - SELECT_LEX *lex_select_save= thd_arg->lex->current_select; + SELECT_LEX *lex_select_save= thd->lex->current_select; SELECT_LEX *sl, *first_sl= first_select(); bool is_recursive= with_element && with_element->is_recursive; bool is_rec_result_table_created= false; @@ -829,9 +832,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, bool instantiate_tmp_table= false; bool single_tvc= !first_sl->next_select() && first_sl->tvc; DBUG_ENTER("st_select_lex_unit::prepare"); - DBUG_ASSERT(thd == thd_arg); DBUG_ASSERT(thd == current_thd); + if (is_recursive && (sl= first_sl->next_select())) + { + SELECT_LEX *next_sl; + for ( ; ; sl= next_sl) + { + next_sl= sl->next_select(); + if (!next_sl) + break; + if (next_sl->with_all_modifier != sl->with_all_modifier) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "mix of ALL and DISTINCT UNION operations in recursive CTE spec"); + DBUG_RETURN(TRUE); + } + } + } + describe= additional_options & SELECT_DESCRIBE; /* @@ -881,7 +900,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, prepared= 1; saved_error= FALSE; - thd_arg->lex->current_select= sl= first_sl; + thd->lex->current_select= sl= first_sl; found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; is_union_select= is_unit_op() || fake_select_lex || single_tvc; @@ -910,7 +929,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, while (last->next_select()) last= last->next_select(); if (!(tmp_result= union_result= - new (thd_arg->mem_root) select_union_direct(thd_arg, sel_result, + new (thd->mem_root) select_union_direct(thd, sel_result, last))) goto err; /* purecov: inspected */ fake_select_lex= NULL; @@ -919,13 +938,24 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, else { if (!is_recursive) - union_result= new (thd_arg->mem_root) select_unit(thd_arg); + union_result= new (thd->mem_root) select_unit(thd); else { with_element->rec_result= - new (thd_arg->mem_root) select_union_recursive(thd_arg); + new (thd->mem_root) select_union_recursive(thd); union_result= with_element->rec_result; - fake_select_lex= NULL; + if (fake_select_lex) + { + if (fake_select_lex->order_list.first || + fake_select_lex->explicit_limit) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "global ORDER_BY/LIMIT in recursive CTE spec"); + goto err; + } + fake_select_lex->cleanup(); + fake_select_lex= NULL; + } } if (!(tmp_result= union_result)) goto err; /* purecov: inspected */ @@ -941,10 +971,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { if (sl->tvc) { - if (sl->tvc->prepare(thd_arg, sl, tmp_result, this)) + if (sl->tvc->prepare(thd, sl, tmp_result, this)) goto err; } - else if (prepare_join(thd_arg, first_sl, tmp_result, additional_options, + else if (prepare_join(thd, first_sl, tmp_result, additional_options, is_union_select)) goto err; types= first_sl->item_list; @@ -955,10 +985,10 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { if (sl->tvc) { - if (sl->tvc->prepare(thd_arg, sl, tmp_result, this)) + if (sl->tvc->prepare(thd, sl, tmp_result, this)) goto err; } - else if (prepare_join(thd_arg, sl, tmp_result, additional_options, + else if (prepare_join(thd, sl, tmp_result, additional_options, is_union_select)) goto err; @@ -978,7 +1008,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { if (with_element) { - if (derived->with->rename_columns_of_derived_unit(thd, this)) + if (derived_arg->with->rename_columns_of_derived_unit(thd, this)) goto err; if (check_duplicate_names(thd, sl->item_list, 0)) goto err; @@ -989,7 +1019,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, if (first_sl->item_list.elements != sl->item_list.elements) { my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER_THD(thd_arg, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), + ER_THD(thd, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0)); goto err; } @@ -998,25 +1028,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { if (!with_element->is_anchor(sl)) sl->uncacheable|= UNCACHEABLE_UNITED; - if(!is_rec_result_table_created && - (!sl->next_select() || - sl->next_select() == with_element->first_recursive)) + if (!is_rec_result_table_created && + (!sl->next_select() || + sl->next_select() == with_element->first_recursive)) { ulonglong create_options; - create_options= (first_sl->options | thd_arg->variables.option_bits | + create_options= (first_sl->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS); // Join data types for all non-recursive parts of a recursive UNION if (join_union_item_types(thd, types, union_part_count + 1)) goto err; if (union_result->create_result_table(thd, &types, MY_TEST(union_distinct), - create_options, &derived->alias, - false, + create_options, + &derived_arg->alias, false, instantiate_tmp_table, false, 0)) goto err; - if (!derived->table) - derived->table= derived->derived_result->table= + if (!derived_arg->table) + derived_arg->table= derived_arg->derived_result->table= with_element->rec_result->rec_tables.head(); with_element->mark_as_with_prepared_anchor(); is_rec_result_table_created= true; @@ -1087,7 +1117,7 @@ cont: } - create_options= (first_sl->options | thd_arg->variables.option_bits | + create_options= (first_sl->options | thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS); /* Force the temporary table to be a MyISAM table if we're going to use @@ -1115,7 +1145,7 @@ cont: Query_arena *arena, backup_arena; arena= thd->activate_stmt_arena_if_needed(&backup_arena); - intersect_mark= new (thd_arg->mem_root) Item_int(thd, 0); + intersect_mark= new (thd->mem_root) Item_int(thd, 0); if (arena) thd->restore_active_arena(arena, &backup_arena); @@ -1137,7 +1167,7 @@ cont: hidden); if (intersect_mark) types.pop(); - if (error) + if (unlikely(error)) goto err; } if (fake_select_lex && !fake_select_lex->first_cond_optimization) @@ -1159,7 +1189,7 @@ cont: result_table_list.maybe_null_exec= save_maybe_null; } - thd_arg->lex->current_select= lex_select_save; + thd->lex->current_select= lex_select_save; if (!item_list.elements) { Query_arena *arena, backup_arena; @@ -1174,7 +1204,7 @@ cont: if (arena) thd->restore_active_arena(arena, &backup_arena); - if (saved_error) + if (unlikely(saved_error)) goto err; if (fake_select_lex != NULL && @@ -1199,7 +1229,7 @@ cont: */ fake_select_lex->item_list= item_list; - thd_arg->lex->current_select= fake_select_lex; + thd->lex->current_select= fake_select_lex; /* We need to add up n_sum_items in order to make the correct @@ -1227,12 +1257,12 @@ cont: } } - thd_arg->lex->current_select= lex_select_save; + thd->lex->current_select= lex_select_save; - DBUG_RETURN(saved_error || thd_arg->is_fatal_error); + DBUG_RETURN(saved_error || thd->is_fatal_error); err: - thd_arg->lex->current_select= lex_select_save; + thd->lex->current_select= lex_select_save; (void) cleanup(); DBUG_RETURN(TRUE); } @@ -1323,7 +1353,7 @@ bool st_select_lex_unit::optimize() saved_error= sl->join->optimize(); } - if (saved_error) + if (unlikely(saved_error)) { thd->lex->current_select= lex_select_save; DBUG_RETURN(saved_error); @@ -1361,7 +1391,7 @@ bool st_select_lex_unit::exec() if (!saved_error && !was_executed) save_union_explain(thd->lex->explain); - if (saved_error) + if (unlikely(saved_error)) DBUG_RETURN(saved_error); if (union_result) @@ -1426,7 +1456,7 @@ bool st_select_lex_unit::exec() saved_error= sl->join->optimize(); } } - if (!saved_error) + if (likely(!saved_error)) { records_at_start= table->file->stats.records; if (sl->tvc) @@ -1437,7 +1467,7 @@ bool st_select_lex_unit::exec() { // This is UNION DISTINCT, so there should be a fake_select_lex DBUG_ASSERT(fake_select_lex != NULL); - if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL)) + if (unlikely(table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))) DBUG_RETURN(TRUE); table->no_keyread=1; } @@ -1446,7 +1476,7 @@ bool st_select_lex_unit::exec() offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : 0); - if (!saved_error) + if (likely(!saved_error)) { examined_rows+= thd->get_examined_row_count(); thd->set_examined_row_count(0); @@ -1457,7 +1487,7 @@ bool st_select_lex_unit::exec() } } } - if (saved_error) + if (unlikely(saved_error)) { thd->lex->current_select= lex_select_save; DBUG_RETURN(saved_error); @@ -1466,7 +1496,7 @@ bool st_select_lex_unit::exec() { /* Needed for the following test and for records_at_start in next loop */ int error= table->file->info(HA_STATUS_VARIABLE); - if(error) + if (unlikely(error)) { table->file->print_error(error, MYF(0)); DBUG_RETURN(1); @@ -1512,7 +1542,8 @@ bool st_select_lex_unit::exec() */ thd->lex->limit_rows_examined_cnt= ULONGLONG_MAX; - if (fake_select_lex != NULL && !thd->is_fatal_error) // Check if EOM + // Check if EOM + if (fake_select_lex != NULL && likely(!thd->is_fatal_error)) { /* Send result to 'result' */ saved_error= true; @@ -1531,8 +1562,9 @@ bool st_select_lex_unit::exec() don't let it allocate the join. Perhaps this is because we need some special parameter values passed to join constructor? */ - if (!(fake_select_lex->join= new JOIN(thd, item_list, - fake_select_lex->options, result))) + if (unlikely(!(fake_select_lex->join= + new JOIN(thd, item_list, fake_select_lex->options, + result)))) { fake_select_lex->table_list.empty(); goto err; @@ -1598,7 +1630,7 @@ bool st_select_lex_unit::exec() } fake_select_lex->table_list.empty(); - if (!saved_error) + if (likely(!saved_error)) { thd->limit_found_rows = (ulonglong)table->file->stats.records + add_rows; thd->inc_examined_row_count(examined_rows); @@ -1659,16 +1691,24 @@ bool st_select_lex_unit::exec_recursive() if (!was_executed) save_union_explain(thd->lex->explain); - if ((saved_error= incr_table->file->ha_delete_all_rows())) - goto err; - if (with_element->level == 0) { + if (!incr_table->is_created() && + instantiate_tmp_table(incr_table, + tmp_table_param->keyinfo, + tmp_table_param->start_recinfo, + &tmp_table_param->recinfo, + 0)) + DBUG_RETURN(1); + incr_table->file->extra(HA_EXTRA_WRITE_CACHE); + incr_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); start= first_select(); if (with_element->with_anchor) end= with_element->first_recursive; } - + else if (unlikely((saved_error= incr_table->file->ha_delete_all_rows()))) + goto err; + for (st_select_lex *sl= start ; sl != end; sl= sl->next_select()) { if (with_element->level) @@ -1693,17 +1733,17 @@ bool st_select_lex_unit::exec_recursive() sl->join->exec(); saved_error= sl->join->error; } - if (!saved_error) + if (likely(!saved_error)) { examined_rows+= thd->get_examined_row_count(); thd->set_examined_row_count(0); - if (union_result->flush()) + if (unlikely(union_result->flush())) { thd->lex->current_select= lex_select_save; DBUG_RETURN(1); } } - if (saved_error) + if (unlikely(saved_error)) { thd->lex->current_select= lex_select_save; goto err; @@ -1869,7 +1909,7 @@ bool st_select_lex_unit::change_result(select_result_interceptor *new_result, List<Item> *st_select_lex_unit::get_column_types(bool for_cursor) { SELECT_LEX *sl= first_select(); - bool is_procedure= MY_TEST(sl->join->procedure); + bool is_procedure= !sl->tvc && sl->join->procedure ; if (is_procedure) { @@ -1904,6 +1944,7 @@ bool st_select_lex::cleanup() cleanup_order(order_list.first); cleanup_order(group_list.first); + cleanup_ftfuncs(this); if (join) { @@ -1919,6 +1960,7 @@ bool st_select_lex::cleanup() } inner_refs_list.empty(); exclude_from_table_unique_test= FALSE; + hidden_bit_fields= 0; DBUG_RETURN(error); } |