diff options
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r-- | sql/sql_update.cc | 175 |
1 files changed, 88 insertions, 87 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 5ccc2384b84..35e1fe24b97 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -95,8 +95,8 @@ bool compare_record(const TABLE *table) /* The storage engine has read all columns, so it's safe to compare all bits - including those not in the write_set. This is cheaper than the field-by-field - comparison done above. + including those not in the write_set. This is cheaper than the + field-by-field comparison done above. */ if (table->s->can_cmp_whole_record) return cmp_record(table,record[1]); @@ -191,7 +191,7 @@ static void prepare_record_for_error_message(int error, TABLE *table) /* Create unique_map with all fields used by that index. */ my_bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE); - table->mark_columns_used_by_index_no_reset(keynr, &unique_map); + table->mark_columns_used_by_index(keynr, &unique_map); /* Subtract read_set and write_set. */ bitmap_subtract(&unique_map, table->read_set); @@ -254,7 +254,7 @@ int mysql_update(THD *thd, ha_rows *found_return, ha_rows *updated_return) { bool using_limit= limit != HA_POS_ERROR; - bool safe_update= MY_TEST(thd->variables.option_bits & OPTION_SAFE_UPDATES); + bool safe_update= thd->variables.option_bits & OPTION_SAFE_UPDATES; bool used_key_is_modified= FALSE, transactional_table, will_batch; bool can_compare_record; int res; @@ -270,6 +270,7 @@ int mysql_update(THD *thd, key_map old_covering_keys; TABLE *table; SQL_SELECT *select= NULL; + SORT_INFO *file_sort= 0; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; ulonglong id; @@ -340,7 +341,8 @@ int mysql_update(THD *thd, if (table_list->is_view()) unfix_fields(fields); - if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0)) + if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), + fields, MARK_COLUMNS_WRITE, 0, 0)) DBUG_RETURN(1); /* purecov: inspected */ if (table_list->view && check_fields(thd, fields)) { @@ -351,15 +353,13 @@ int mysql_update(THD *thd, my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); DBUG_RETURN(1); } - if (table->default_field) - table->mark_default_fields_for_write(); #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Check values */ table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); #endif - if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0)) { free_underlaid_joins(thd, select_lex); DBUG_RETURN(1); /* purecov: inspected */ @@ -371,7 +371,7 @@ int mysql_update(THD *thd, switch_to_nullable_trigger_fields(fields, table); switch_to_nullable_trigger_fields(values, table); - /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ + /* Apply the IN=>EXISTS transformation to all subqueries and optimize them */ if (select_lex->optimize_unflattened_subqueries(false)) DBUG_RETURN(TRUE); @@ -392,14 +392,6 @@ int mysql_update(THD *thd, } } - /* - If a timestamp field settable on UPDATE is present then to avoid wrong - update force the table handler to retrieve write-only fields to be able - to compare records and detect data change. - */ - if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) && - table->default_field && table->has_default_function(true)) - bitmap_union(table->read_set, table->write_set); // Don't count on usage of 'only index' when calculating which key to use table->covering_keys.clear_all(); @@ -420,7 +412,7 @@ int mysql_update(THD *thd, table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); set_statistics_for_table(thd, table); - select= make_select(table, 0, 0, conds, 0, &error); + select= make_select(table, 0, 0, conds, (SORT_INFO*) 0, 0, &error); if (error || !limit || thd->is_error() || (select && select->check_quick(thd, safe_update, limit))) { @@ -542,16 +534,9 @@ int mysql_update(THD *thd, /* We can't update table directly; We must first search after all matching rows before updating the table! - */ - MY_BITMAP *save_read_set= table->read_set; - MY_BITMAP *save_write_set= table->write_set; - - if (query_plan.index < MAX_KEY && old_covering_keys.is_set(query_plan.index)) - table->add_read_columns_used_by_index(query_plan.index); - else - table->use_all_columns(); - /* note: We avoid sorting if we sort on the used index */ + note: We avoid sorting if we sort on the used index + */ if (query_plan.using_filesort) { /* @@ -559,28 +544,15 @@ int mysql_update(THD *thd, to update NOTE: filesort will call table->prepare_for_position() */ - uint length= 0; - SORT_FIELD *sortorder; - ha_rows examined_rows; - ha_rows found_rows; - - table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL | - MY_THREAD_SPECIFIC)); + Filesort fsort(order, limit, true, select); + Filesort_tracker *fs_tracker= thd->lex->explain->get_upd_del_plan()->filesort_tracker; - if (!(sortorder=make_unireg_sortorder(thd, NULL, 0, order, &length, NULL)) || - (table->sort.found_records= filesort(thd, table, sortorder, length, - select, limit, - true, - &examined_rows, &found_rows, - fs_tracker)) - == HA_POS_ERROR) - { + if (!(file_sort= filesort(thd, table, &fsort, fs_tracker))) goto err; - } - thd->inc_examined_row_count(examined_rows); + thd->inc_examined_row_count(file_sort->examined_rows); + /* Filesort has already found and selected the rows we want to update, so we don't need the where clause @@ -590,6 +562,14 @@ int mysql_update(THD *thd, } else { + MY_BITMAP *save_read_set= table->read_set; + MY_BITMAP *save_write_set= table->write_set; + + if (query_plan.index < MAX_KEY && old_covering_keys.is_set(query_plan.index)) + table->prepare_for_keyread(query_plan.index); + else + table->use_all_columns(); + /* We are doing a search on a key that is updated. In this case we go trough the matching rows, save a pointer to them and @@ -622,7 +602,7 @@ int mysql_update(THD *thd, */ if (query_plan.index == MAX_KEY || (select && select->quick)) - error= init_read_record(&info, thd, table, select, 0, 1, FALSE); + error= init_read_record(&info, thd, table, select, NULL, 0, 1, FALSE); else error= init_read_record_idx(&info, thd, table, 1, query_plan.index, reverse); @@ -639,8 +619,6 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { explain->buf_tracker.on_record_read(); - if (table->vfield) - update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->inc_examined_row_count(1); if (!select || (error= select->skip_record(thd)) > 0) { @@ -664,8 +642,9 @@ int mysql_update(THD *thd, else { /* - Don't try unlocking the row if skip_record reported an error since in - this case the transaction might have been rolled back already. + Don't try unlocking the row if skip_record reported an + error since in this case the transaction might have been + rolled back already. */ if (error < 0) { @@ -703,9 +682,10 @@ int mysql_update(THD *thd, select->file=tempfile; // Read row ptrs from this file if (error >= 0) goto err; + + table->file->ha_end_keyread(); + table->column_bitmaps_set(save_read_set, save_write_set); } - table->disable_keyread(); - table->column_bitmaps_set(save_read_set, save_write_set); } if (ignore) @@ -714,7 +694,7 @@ int mysql_update(THD *thd, if (select && select->quick && select->quick->reset()) goto err; table->file->try_semi_consistent_read(1); - if (init_read_record(&info, thd, table, select, 0, 1, FALSE)) + if (init_read_record(&info, thd, table, select, file_sort, 0, 1, FALSE)) goto err; updated= found= 0; @@ -755,8 +735,6 @@ int mysql_update(THD *thd, while (!(error=info.read_record(&info)) && !thd->killed) { explain->tracker.on_record_read(); - if (table->vfield) - update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ); thd->inc_examined_row_count(1); if (!select || select->skip_record(thd) > 0) { @@ -773,7 +751,7 @@ int mysql_update(THD *thd, if (!can_compare_record || compare_record(table)) { - if (table->default_field && table->update_default_fields()) + if (table->default_field && table->update_default_fields(1, ignore)) { error= 1; break; @@ -1020,6 +998,7 @@ int mysql_update(THD *thd, } DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); + delete file_sort; /* If LAST_INSERT_ID(X) was used, report X */ id= thd->arg_of_last_insert_id_function ? @@ -1053,8 +1032,9 @@ int mysql_update(THD *thd, err: delete select; + delete file_sort; free_underlaid_joins(thd, select_lex); - table->disable_keyread(); + table->file->ha_end_keyread(); thd->abort_on_warning= 0; DBUG_RETURN(1); @@ -1242,10 +1222,8 @@ bool unsafe_key_update(List<TABLE_LIST> leaves, table_map tables_for_update) { // Partitioned key is updated my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0), - tl->belong_to_view ? tl->belong_to_view->alias - : tl->alias, - tl2->belong_to_view ? tl2->belong_to_view->alias - : tl2->alias); + tl->top_table()->alias, + tl2->top_table()->alias); return true; } @@ -1263,10 +1241,8 @@ bool unsafe_key_update(List<TABLE_LIST> leaves, table_map tables_for_update) { // Clustered primary key is updated my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0), - tl->belong_to_view ? tl->belong_to_view->alias - : tl->alias, - tl2->belong_to_view ? tl2->belong_to_view->alias - : tl2->alias); + tl->top_table()->alias, + tl2->top_table()->alias); return true; } } @@ -1428,7 +1404,8 @@ int mysql_multi_update_prepare(THD *thd) if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(TRUE); - if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0)) + if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), + *fields, MARK_COLUMNS_WRITE, 0, 0)) DBUG_RETURN(TRUE); for (tl= table_list; tl ; tl= tl->next_local) @@ -1466,11 +1443,13 @@ int mysql_multi_update_prepare(THD *thd) { if (!tl->single_table_updatable() || check_key_in_view(thd, tl)) { - my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE"); + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), + tl->top_table()->alias, "UPDATE"); DBUG_RETURN(TRUE); } - DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); + DBUG_PRINT("info",("setting table `%s` for update", + tl->top_table()->alias)); /* If table will be updated we should not downgrade lock for it and leave it as is. @@ -1615,7 +1594,7 @@ bool mysql_multi_update(THD *thd, thd->abort_on_warning= !ignore && thd->is_strict_mode(); List<Item> total_list; - res= mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, table_list, select_lex->with_wild, total_list, conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, @@ -1711,7 +1690,8 @@ int multi_update::prepare(List<Item> ¬_used_values, reference tables */ - int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0); + int error= setup_fields(thd, Ref_ptr_array(), + *values, MARK_COLUMNS_READ, 0, 0); ti.rewind(); while ((table_ref= ti++)) @@ -1724,17 +1704,8 @@ int multi_update::prepare(List<Item> ¬_used_values, { table->read_set= &table->def_read_set; bitmap_union(table->read_set, &table->tmp_set); - /* - If a timestamp field settable on UPDATE is present then to avoid wrong - update force the table handler to retrieve write-only fields to be able - to compare records and detect data change. - */ - if ((table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) && - table->default_field && table->has_default_function(true)) - bitmap_union(table->read_set, table->write_set); } } - if (error) DBUG_RETURN(1); @@ -1827,6 +1798,21 @@ void multi_update::update_used_tables() } } +void multi_update::prepare_to_read_rows() +{ + /* + update column maps now. it cannot be done in ::prepare() before the + optimizer, because the optimize might reset them (in + SELECT_LEX::update_used_tables()), it cannot be done in + ::initialize_tables() after the optimizer, because the optimizer + might read rows from const tables + */ + + for (TABLE_LIST *tl= update_tables; tl; tl= tl->next_local) + tl->table->mark_columns_needed_for_update(); +} + + /* Check if table is safe to update on fly @@ -1943,12 +1929,10 @@ multi_update::initialize_tables(JOIN *join) { if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables)) { - table->mark_columns_needed_for_update(); table_to_update= table; // Update table on the fly continue; } } - table->mark_columns_needed_for_update(); table->prepare_for_position(); /* @@ -2038,7 +2022,7 @@ loop_end: /* Make an unique key over the first field to avoid duplicated updates */ bzero((char*) &group, sizeof(group)); - group.asc= 1; + group.direction= ORDER::ORDER_ASC; group.item= (Item**) temp_fields.head_ref(); tmp_param->quick_group=1; @@ -2125,11 +2109,11 @@ int multi_update::send_data(List<Item> ¬_used_values) table->status|= STATUS_UPDATED; store_record(table,record[1]); - if (fill_record_n_invoke_before_triggers(thd, table, *fields_for_table[offset], + if (fill_record_n_invoke_before_triggers(thd, table, + *fields_for_table[offset], *values_for_table[offset], 0, TRG_EVENT_UPDATE)) DBUG_RETURN(1); - /* Reset the table->auto_increment_field_not_null as it is valid for only one row. @@ -2140,7 +2124,7 @@ int multi_update::send_data(List<Item> ¬_used_values) { int error; - if (table->default_field && table->update_default_fields()) + if (table->default_field && table->update_default_fields(1, ignore)) DBUG_RETURN(1); if ((error= cur_table->view_check_option(thd, ignore)) != @@ -2341,6 +2325,17 @@ int multi_update::do_updates() goto err; } table->file->extra(HA_EXTRA_NO_CACHE); + /* + We have to clear the base record, if we have virtual indexed + blob fields, as some storage engines will access the blob fields + to calculate the keys to see if they have changed. Without + clearing the blob pointers will contain random values which can + cause a crash. + This is a workaround for engines that access columns not present in + either read or write set. + */ + if (table->vfield) + empty_record(table); check_opt_it.rewind(); while(TABLE *tbl= check_opt_it++) @@ -2410,6 +2405,11 @@ int multi_update::do_updates() field_num++; } while ((tbl= check_opt_it++)); + if (table->vfield && + table->update_virtual_fields(table->file, + VCOL_UPDATE_INDEXED_FOR_UPDATE)) + goto err2; + table->status|= STATUS_UPDATED; store_record(table,record[1]); @@ -2430,10 +2430,11 @@ int multi_update::do_updates() if (!can_compare_record || compare_record(table)) { int error; - if (table->default_field && (error= table->update_default_fields())) + if (table->default_field && + (error= table->update_default_fields(1, ignore))) goto err2; if (table->vfield && - update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE)) + table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE)) goto err2; if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) |