diff options
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r-- | sql/sql_update.cc | 162 |
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> ¬_used_values) +int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) { TABLE_LIST *table_ref; SQL_LIST update; @@ -478,7 +504,7 @@ int multi_update::prepare(List<Item> ¬_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> ¬_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> ¬_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> ¬_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> ¬_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> ¬_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; |