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.cc162
1 files changed, 96 insertions, 66 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 3179c8e0f24..199693df7d6 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -30,7 +30,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
static bool compare_record(TABLE *table, ulong query_id)
{
if (!table->blob_fields)
- return cmp_record(table,1);
+ return cmp_record(table,record[1]);
/* Compare null bits */
if (memcmp(table->null_flags,
table->null_flags+table->rec_buff_length,
@@ -52,7 +52,7 @@ int mysql_update(THD *thd,
List<Item> &fields,
List<Item> &values,
COND *conds,
- ORDER *order,
+ uint order_num, ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates)
{
@@ -67,17 +67,21 @@ int mysql_update(THD *thd,
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
- TABLE_LIST tables;
- List<Item> all_fields;
+ TABLE_LIST *update_table_list= ((TABLE_LIST*)
+ thd->lex.select_lex.table_list.first);
+ TABLE_LIST tables;
+ List<Item> all_fields;
DBUG_ENTER("mysql_update");
LINT_INIT(used_index);
LINT_INIT(timestamp_query_id);
- if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
- DBUG_RETURN(-1); /* purecov: inspected */
- table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ if ((open_and_lock_tables(thd, table_list)))
+ DBUG_RETURN(-1);
thd->proc_info="init";
+ fix_tables_pointers(thd->lex.all_selects_list);
+ table= table_list->table;
+ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys=table->keys_in_use;
@@ -89,12 +93,24 @@ int mysql_update(THD *thd,
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(table_list) || setup_conds(thd,table_list,&conds) ||
- setup_order(thd, &tables, all_fields, all_fields, order) ||
- setup_ftfuncs(thd))
+ if (setup_tables(update_table_list) ||
+ setup_conds(thd,update_table_list,&conds) ||
+ setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
+ order_num) ||
+ setup_order(thd, thd->lex.select_lex.ref_pointer_array,
+ &tables, all_fields, all_fields, order) ||
+ setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1); /* purecov: inspected */
- old_used_keys=table->used_keys; // Keys used in WHERE
+ /* Check that we are not using table that we are updating in a sub select */
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+
+ old_used_keys= table->used_keys; // Keys used in WHERE
/*
Change the query_id for the timestamp column so that we can
check if this is modified directly
@@ -108,7 +124,7 @@ int mysql_update(THD *thd,
/* Check the fields we are going to modify */
table->grant.want_privilege=want_privilege;
- if (setup_fields(thd,table_list,fields,1,0,0))
+ if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
{
@@ -121,8 +137,9 @@ int mysql_update(THD *thd,
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_fields(thd,table_list,values,0,0,0))
+ if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
{
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1); /* purecov: inspected */
}
@@ -133,11 +150,12 @@ int mysql_update(THD *thd,
(select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
if (error)
{
DBUG_RETURN(-1); // Error in where
}
- send_ok(&thd->net); // No matching records
+ send_ok(thd); // No matching records
DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
@@ -146,12 +164,12 @@ int mysql_update(THD *thd,
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
{
- delete select;
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- DBUG_RETURN(1);
+ my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
+ ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
+ goto err;
}
}
- init_ftfuncs(thd,1);
+ init_ftfuncs(thd, &thd->lex.select_lex, 1);
/* Check if we are modifying a key that we are used to search with */
if (select && select->quick)
used_key_is_modified= (!select->quick->unique_key_range() &&
@@ -185,13 +203,13 @@ int mysql_update(THD *thd,
SORT_FIELD *sortorder;
ha_rows examined_rows;
- table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
- MYF(MY_FAE | MY_ZEROFILL));
+ table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
+ MYF(MY_FAE | MY_ZEROFILL));
if (!(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->found_records = filesort(table, sortorder, length,
- select, 0L,
- limit, &examined_rows)) ==
- HA_POS_ERROR)
+ (table->sort.found_records = filesort(thd, table, sortorder, length,
+ select, limit,
+ &examined_rows))
+ == HA_POS_ERROR)
{
free_io_cache(table);
goto err;
@@ -219,6 +237,7 @@ int mysql_update(THD *thd,
init_read_record(&info,thd,table,select,0,1);
thd->proc_info="Searching rows for update";
uint tmp_limit= limit;
+
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (!(select && select->skipp_record()))
@@ -280,8 +299,8 @@ int mysql_update(THD *thd,
{
if (!(select && select->skipp_record()))
{
- store_record(table,1);
- if (fill_record(fields, values, 0))
+ store_record(table,record[1]);
+ if (fill_record(fields,values, 0) || thd->net.report_error)
break; /* purecov: inspected */
found++;
if (compare_record(table, query_id))
@@ -307,11 +326,20 @@ int mysql_update(THD *thd,
}
else
table->file->unlock_row();
+ thd->row_count++;
}
end_read_record(&info);
free_io_cache(table); // If ORDER BY
thd->proc_info="end";
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
+
+ /*
+ Invalidate the table in the query cache if something changed.
+ This must be before binlog writing and ha_autocommit_...
+ */
+ if (updated)
+ query_cache_invalidate3(thd, table_list, 1);
+
transactional_table= table->file->has_transactions();
log_delayed= (transactional_table || table->tmp_table);
if (updated && (error <= 0 || !transactional_table))
@@ -333,14 +361,6 @@ int mysql_update(THD *thd,
error=1;
}
- /*
- Store table for future invalidation or invalidate it in
- the query cache if something changed
- */
- if (updated)
- {
- query_cache_invalidate3(thd, table_list, 1);
- }
if (thd->lock)
{
mysql_unlock_tables(thd, thd->lock);
@@ -348,14 +368,15 @@ int mysql_update(THD *thd,
}
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
if (error >= 0)
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
else
{
char buff[80];
- sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
- (long) thd->cuted_fields);
- send_ok(&thd->net,
+ sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
+ (ulong) thd->cuted_fields);
+ send_ok(thd,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
DBUG_PRINT("info",("%d records updated",updated));
@@ -366,6 +387,7 @@ int mysql_update(THD *thd,
err:
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
if (table->key_read)
{
table->key_read=0;
@@ -389,7 +411,8 @@ int mysql_multi_update(THD *thd,
List<Item> *values,
COND *conds,
ulong options,
- enum enum_duplicates handle_duplicates)
+ enum enum_duplicates handle_duplicates,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
int res;
multi_update *result;
@@ -399,15 +422,16 @@ int mysql_multi_update(THD *thd,
table_list->grant.want_privilege=(SELECT_ACL & ~table_list->grant.privilege);
if ((res=open_and_lock_tables(thd,table_list)))
DBUG_RETURN(res);
+ fix_tables_pointers(thd->lex.all_selects_list);
thd->select_limit=HA_POS_ERROR;
- if (setup_fields(thd, table_list, *fields, 1, 0, 0))
+ if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
DBUG_RETURN(-1);
/*
Count tables and setup timestamp handling
*/
- for (tl= (TABLE_LIST*) table_list ; tl ; tl=tl->next)
+ for (tl= select_lex->get_table_list() ; tl ; tl=tl->next)
{
TABLE *table= tl->table;
if (table->timestamp_field)
@@ -424,11 +448,13 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(-1);
List<Item> total_list;
- res= mysql_select(thd,table_list,total_list,
- conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ select_lex->get_table_list(), select_lex->with_wild,
+ total_list,
+ conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
- result);
+ result, unit, select_lex, 0);
delete result;
DBUG_RETURN(res);
}
@@ -448,7 +474,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
Connect fields with tables and create list of tables that are updated
*/
-int multi_update::prepare(List<Item> &not_used_values)
+int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
{
TABLE_LIST *table_ref;
SQL_LIST update;
@@ -478,7 +504,7 @@ int multi_update::prepare(List<Item> &not_used_values)
reference tables
*/
- if (setup_fields(thd, all_tables, *values, 1,0,0))
+ if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0))
DBUG_RETURN(1);
/*
@@ -516,14 +542,14 @@ int multi_update::prepare(List<Item> &not_used_values)
table_count);
values_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
table_count);
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
for (i=0 ; i < table_count ; i++)
{
fields_for_table[i]= new List_item;
values_for_table[i]= new List_item;
}
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
/* Split fields into fields_for_table[] and values_by_table[] */
@@ -536,7 +562,7 @@ int multi_update::prepare(List<Item> &not_used_values)
fields_for_table[offset]->push_back(item);
values_for_table[offset]->push_back(value);
}
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
/* Allocate copy fields */
@@ -544,7 +570,7 @@ int multi_update::prepare(List<Item> &not_used_values)
for (i=0 ; i < table_count ; i++)
set_if_bigger(max_fields, fields_for_table[i]->elements);
copy_field= new Copy_field[max_fields];
- DBUG_RETURN(thd->fatal_error != 0);
+ DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -597,7 +623,7 @@ multi_update::initialize_tables(JOIN *join)
/* ok to be on stack as this is not referenced outside of this func */
Field_string offset(table->file->ref_length, 0, "offset",
- table, 1);
+ table, &my_charset_bin);
if (temp_fields.push_front(new Item_field(((Field *) &offset))))
DBUG_RETURN(1);
@@ -613,8 +639,9 @@ multi_update::initialize_tables(JOIN *join)
if (!(tmp_tables[cnt]=create_tmp_table(thd,
tmp_param,
temp_fields,
- (ORDER*) &group, 0, 0, 0,
- TMP_TABLE_ALL_COLUMNS)))
+ (ORDER*) &group, 0, 0,
+ TMP_TABLE_ALL_COLUMNS,
+ HA_POS_ERROR)))
DBUG_RETURN(1);
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
@@ -675,7 +702,6 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
}
-
multi_update::~multi_update()
{
TABLE_LIST *table;
@@ -729,8 +755,8 @@ bool multi_update::send_data(List<Item> &not_used_values)
if (table == table_to_update)
{
table->status|= STATUS_UPDATED;
- store_record(table,1);
- if (fill_record(*fields_for_table[offset], *values_for_table[offset],0 ))
+ store_record(table,record[1]);
+ if (fill_record(*fields_for_table[offset], *values_for_table[offset], 0))
DBUG_RETURN(1);
found++;
if (compare_record(table, thd->query_id))
@@ -784,7 +810,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
void multi_update::send_error(uint errcode,const char *err)
{
/* First send error what ever it is ... */
- ::send_error(&thd->net,errcode,err);
+ ::send_error(thd,errcode,err);
/* If nothing updated return */
if (!updated)
@@ -861,7 +887,7 @@ int multi_update::do_updates(bool from_send_error)
if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
goto err;
table->status|= STATUS_UPDATED;
- store_record(table,1);
+ store_record(table,record[1]);
/* Copy data from temporary table to current table */
for (copy_field_ptr=copy_field;
@@ -924,6 +950,14 @@ bool multi_update::send_eof()
int local_error = (table_count) ? do_updates(0) : 0;
thd->proc_info= "end";
+ /* We must invalidate the query cache before binlog writing and
+ ha_autocommit_... */
+
+ if (updated)
+ {
+ query_cache_invalidate3(thd, update_tables, 1);
+ }
+
/*
Write the SQL statement to the binlog if we updated
rows and we succeeded or if we updated some non
@@ -955,18 +989,14 @@ bool multi_update::send_eof()
/* Safety: If we haven't got an error before (should not happen) */
my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
MYF(0));
- ::send_error(&thd->net);
+ ::send_error(thd);
return 1;
}
- sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
- (long) thd->cuted_fields);
- if (updated)
- {
- query_cache_invalidate3(thd, update_tables, 1);
- }
- ::send_ok(&thd->net,
+ sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
+ (ulong) thd->cuted_fields);
+ ::send_ok(thd,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
return 0;