summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc175
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> &not_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> &not_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> &not_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> &not_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)