sql_update.cc 52.6 KB
Newer Older
1
/* Copyright (C) 2000-2006 MySQL AB
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


17 18 19
/*
  Single table and multi table updates of tables.
  Multi-table updates were introduced by Sinisa & Monty
20
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
21 22

#include "mysql_priv.h"
23
#include "sql_select.h"
24 25
#include "sp_head.h"
#include "sql_trigger.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26 27 28

/* Return 0 if row hasn't changed */

igor@olga.mysql.com's avatar
igor@olga.mysql.com committed
29
bool compare_record(TABLE *table)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
30
{
31
  if (table->s->blob_fields + table->s->varchar_fields == 0)
32
    return cmp_record(table,record[1]);
33
  /* Compare null bits */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
34
  if (memcmp(table->null_flags,
35 36
	     table->null_flags+table->s->rec_buff_length,
	     table->s->null_bytes))
37
    return TRUE;				// Diff in NULL value
38
  /* Compare updated fields */
39
  for (Field **ptr= table->field ; *ptr ; ptr++)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
40
  {
41
    if (bitmap_is_set(table->write_set, (*ptr)->field_index) &&
42
	(*ptr)->cmp_binary_offset(table->s->rec_buff_length))
43
      return TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
44
  }
45
  return FALSE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
46 47 48
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
49 50 51 52 53
/*
  check that all fields are real fields

  SYNOPSIS
    check_fields()
54
    thd             thread handler
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
55 56 57 58 59 60 61
    items           Items for check

  RETURN
    TRUE  Items can't be used in UPDATE
    FALSE Items are OK
*/

62
static bool check_fields(THD *thd, List<Item> &items)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
63
{
64
  List_iterator<Item> it(items);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
65
  Item *item;
66
  Item_field *field;
67

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
68 69
  while ((item= it++))
  {
70
    if (!(field= item->filed_for_view_update()))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
71
    {
72
      /* item has name, because it comes from VIEW SELECT list */
73
      my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
74 75
      return TRUE;
    }
76 77 78 79
    /*
      we make temporary copy of Item_field, to avoid influence of changing
      result_field on Item_ref which refer on this field
    */
monty@mysql.com's avatar
monty@mysql.com committed
80
    thd->change_item_tree(it.ref(), new Item_field(thd, field));
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
81 82 83 84 85
  }
  return FALSE;
}


86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/*
  Process usual UPDATE

  SYNOPSIS
    mysql_update()
    thd			thread handler
    fields		fields for update
    values		values of fields for update
    conds		WHERE clause expression
    order_num		number of elemen in ORDER BY clause
    order		ORDER BY clause list
    limit		limit clause
    handle_duplicates	how to handle duplicates

  RETURN
    0  - OK
    2  - privilege check and openning table passed, but we need to convert to
         multi-update because of view substitution
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
104
    1  - error
105 106
*/

107 108 109 110 111
int mysql_update(THD *thd,
                 TABLE_LIST *table_list,
                 List<Item> &fields,
		 List<Item> &values,
                 COND *conds,
112
                 uint order_num, ORDER *order,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
113
		 ha_rows limit,
114
		 enum enum_duplicates handle_duplicates, bool ignore)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
115
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
116
  bool		using_limit= limit != HA_POS_ERROR;
117
  bool		safe_update= test(thd->options & OPTION_SAFE_UPDATES);
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
118
  bool		used_key_is_modified, transactional_table, will_batch;
119
  bool		can_compare_record;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
120
  int           res;
121 122
  int		error, loc_error;
  uint		used_index= MAX_KEY, dup_key_found;
123
  bool          need_sort= TRUE;
124 125 126
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  uint		want_privilege;
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
127
  uint          table_count= 0;
128
  ha_rows	updated, found;
129
  key_map	old_covering_keys;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
130 131 132
  TABLE		*table;
  SQL_SELECT	*select;
  READ_RECORD	info;
133
  SELECT_LEX    *select_lex= &thd->lex->select_lex;
134 135
  bool          need_reopen;
  ulonglong     id;
136
  List<Item> all_fields;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
137
  DBUG_ENTER("mysql_update");
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
138

139
  for ( ; ; )
140
  {
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    if (open_tables(thd, &table_list, &table_count, 0))
      DBUG_RETURN(1);

    if (table_list->multitable_view)
    {
      DBUG_ASSERT(table_list->view != 0);
      DBUG_PRINT("info", ("Switch to multi-update"));
      /* pass counter value */
      thd->lex->table_count= table_count;
      /* convert to multiupdate */
      DBUG_RETURN(2);
    }
    if (!lock_tables(thd, table_list, table_count, &need_reopen))
      break;
    if (!need_reopen)
      DBUG_RETURN(1);
157
    close_tables_for_reopen(thd, &table_list);
158
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
159

160
  if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
161 162
      (thd->fill_derived_tables() &&
       mysql_handle_derived(thd->lex, &mysql_derived_filling)))
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
163
    DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
164

bk@work.mysql.com's avatar
bk@work.mysql.com committed
165
  thd->proc_info="init";
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
166
  table= table_list->table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
167

168 169
  /* Calculate "table->covering_keys" based on the WHERE */
  table->covering_keys= table->s->keys_in_use;
170
  table->quick_keys.clear_all();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
171

hf@deer.(none)'s avatar
hf@deer.(none) committed
172
#ifndef NO_EMBEDDED_ACCESS_CHECKS
173 174 175
  /* Force privilege re-checking for views after they have been opened. */
  want_privilege= (table_list->view ? UPDATE_ACL :
                   table_list->grant.want_privilege);
hf@deer.(none)'s avatar
hf@deer.(none) committed
176
#endif
177
  if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
178
    DBUG_RETURN(1);
179

180
  old_covering_keys= table->covering_keys;		// Keys used in WHERE
181
  /* Check the fields we are going to modify */
hf@deer.(none)'s avatar
hf@deer.(none) committed
182
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
183
  table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
184
  table_list->register_want_access(want_privilege);
hf@deer.(none)'s avatar
hf@deer.(none) committed
185
#endif
186
  if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0))
187
    DBUG_RETURN(1);                     /* purecov: inspected */
188
  if (table_list->view && check_fields(thd, fields))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
189
  {
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
190
    DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
191 192 193
  }
  if (!table_list->updatable || check_key_in_view(thd, table_list))
  {
194
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
195
    DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
196
  }
197 198 199
  if (table->timestamp_field)
  {
    // Don't set timestamp column if this is modified
200 201
    if (bitmap_is_set(table->write_set,
                      table->timestamp_field->field_index))
202
      table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
203
    else
204
    {
205 206 207 208
      if (table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_UPDATE ||
          table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH)
        bitmap_set_bit(table->write_set,
                       table->timestamp_field->field_index);
209
    }
210
  }
211

hf@deer.(none)'s avatar
hf@deer.(none) committed
212
#ifndef NO_EMBEDDED_ACCESS_CHECKS
213
  /* Check values */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
214
  table_list->grant.want_privilege= table->grant.want_privilege=
215
    (SELECT_ACL & ~table->grant.privilege);
hf@deer.(none)'s avatar
hf@deer.(none) committed
216
#endif
217
  if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
218
  {
219
    free_underlaid_joins(thd, select_lex);
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
220
    DBUG_RETURN(1);				/* purecov: inspected */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
221
  }
222

223 224 225 226
  if (select_lex->inner_refs_list.elements &&
    fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
    DBUG_RETURN(-1);

227 228 229 230 231 232 233
  if (conds)
  {
    Item::cond_result cond_value;
    conds= remove_eq_conds(thd, conds, &cond_value);
    if (cond_value == Item::COND_FALSE)
      limit= 0;                                   // Impossible WHERE
  }
234
  // Don't count on usage of 'only index' when calculating which key to use
235
  table->covering_keys.clear_all();
236 237 238 239 240 241 242 243 244

#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (prune_partitions(thd, table, conds))
  {
    free_underlaid_joins(thd, select_lex);
    send_ok(thd);				// No matching records
    DBUG_RETURN(0);
  }
#endif
245
  /* Update the table->file->stats.records number */
246
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
247

monty@mysql.com's avatar
monty@mysql.com committed
248
  select= make_select(table, 0, 0, conds, 0, &error);
249 250
  if (error || !limit ||
      (select && select->check_quick(thd, safe_update, limit)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
251 252
  {
    delete select;
253
    free_underlaid_joins(thd, select_lex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
254 255
    if (error)
    {
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
256
      DBUG_RETURN(1);				// Error in where
bk@work.mysql.com's avatar
bk@work.mysql.com committed
257
    }
258
    send_ok(thd);				// No matching records
bk@work.mysql.com's avatar
bk@work.mysql.com committed
259 260
    DBUG_RETURN(0);
  }
261 262
  if (!select && limit != HA_POS_ERROR)
  {
263
    if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY)
264 265
      need_sort= FALSE;
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
266
  /* If running in safe sql mode, don't allow updates without keys */
267
  if (table->quick_keys.is_clear_all())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
268
  {
269
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
270
    if (safe_update && !using_limit)
271
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
272 273 274
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
		 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
      goto err;
275
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
276
  }
277
  init_ftfuncs(thd, select_lex, 1);
278 279 280

  table->mark_columns_needed_for_update();

bk@work.mysql.com's avatar
bk@work.mysql.com committed
281
  /* Check if we are modifying a key that we are used to search with */
282
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
283
  if (select && select->quick)
284
  {
285
    used_index= select->quick->index;
286
    used_key_is_modified= (!select->quick->unique_key_range() &&
287
                          select->quick->is_keys_used(table->write_set));
288
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
289
  else
290
  {
291 292 293 294
    used_key_is_modified= 0;
    if (used_index == MAX_KEY)                  // no index for sort order
      used_index= table->file->key_used_on_scan;
    if (used_index != MAX_KEY)
295
      used_key_is_modified= is_key_used(table, used_index, table->write_set);
296
  }
297

298

299
#ifdef WITH_PARTITION_STORAGE_ENGINE
300
  if (used_key_is_modified || order ||
301
      partition_key_modified(table, table->write_set))
302
#else
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
303
  if (used_key_is_modified || order)
304
#endif
bk@work.mysql.com's avatar
bk@work.mysql.com committed
305 306
  {
    /*
307 308
      We can't update table directly;  We must first search after all
      matching rows before updating the table!
bk@work.mysql.com's avatar
bk@work.mysql.com committed
309
    */
310
    if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
311 312
    {
      table->key_read=1;
313 314 315 316 317
      table->mark_columns_used_by_index(used_index);
    }
    else
    {
      table->use_all_columns();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
318
    }
319

320
    /* note: We avoid sorting avoid if we sort on the used index */
321
    if (order && (need_sort || used_key_is_modified))
322
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
323 324 325
      /*
	Doing an ORDER BY;  Let filesort find and sort the rows we are going
	to update
326
        NOTE: filesort will call table->prepare_for_position()
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
327
      */
328
      uint         length= 0;
329
      SORT_FIELD  *sortorder;
330
      ha_rows examined_rows;
331

igor@hundin.mysql.fi's avatar
igor@hundin.mysql.fi committed
332
      table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
333
						    MYF(MY_FAE | MY_ZEROFILL));
334
      if (!(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
335 336 337
          (table->sort.found_records= filesort(thd, table, sortorder, length,
                                               select, limit, 1,
                                               &examined_rows))
338 339
          == HA_POS_ERROR)
      {
340
	goto err;
341
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
342 343 344 345 346 347
      /*
	Filesort has already found and selected the rows we want to update,
	so we don't need the where clause
      */
      delete select;
      select= 0;
348
    }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
349
    else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
350
    {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
351 352 353 354 355 356 357 358 359
      /*
	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
	update these in a separate loop based on the pointer.
      */

      IO_CACHE tempfile;
      if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
			   DISK_BUFFER_SIZE, MYF(MY_WME)))
360
	goto err;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
361

sergefp@mysql.com's avatar
sergefp@mysql.com committed
362 363 364
      /* If quick select is used, initialize it before retrieving rows. */
      if (select && select->quick && select->quick->reset())
        goto err;
365
      table->file->try_semi_consistent_read(1);
366

367 368 369 370 371 372 373 374 375 376
      /*
        When we get here, we have one of the following options:
        A. used_index == MAX_KEY
           This means we should use full table scan, and start it with
           init_read_record call
        B. used_index != MAX_KEY
           B.1 quick select is used, start the scan with init_read_record
           B.2 quick select is not used, this is full index scan (with LIMIT)
               Full index scan must be started with init_read_record_idx
      */
377

378
      if (used_index == MAX_KEY || (select && select->quick))
379 380 381
        init_read_record(&info,thd,table,select,0,1);
      else
        init_read_record_idx(&info, thd, table, 1, used_index);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
382

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
383 384
      thd->proc_info="Searching rows for update";
      uint tmp_limit= limit;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
385

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
386
      while (!(error=info.read_record(&info)) && !thd->killed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
387
      {
388
	if (!(select && select->skip_record()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
389
	{
390 391 392
          if (table->file->was_semi_consistent_read())
	    continue;  /* repeat the read of the same row if it still exists */

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
393 394 395 396 397 398 399 400
	  table->file->position(table->record[0]);
	  if (my_b_write(&tempfile,table->file->ref,
			 table->file->ref_length))
	  {
	    error=1; /* purecov: inspected */
	    break; /* purecov: inspected */
	  }
	  if (!--limit && using_limit)
401 402
	  {
	    error= -1;
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
403
	    break;
404
	  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
405
	}
marko@hundin.mysql.fi's avatar
marko@hundin.mysql.fi committed
406 407
	else
	  table->file->unlock_row();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
408
      }
409 410
      if (thd->killed && !error)
	error= 1;				// Aborted
411
      limit= tmp_limit;
412
      table->file->try_semi_consistent_read(0);
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
413
      end_read_record(&info);
414
     
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
415 416 417 418 419 420 421 422 423
      /* Change select to use tempfile */
      if (select)
      {
	delete select->quick;
	if (select->free_cond)
	  delete select->cond;
	select->quick=0;
	select->cond=0;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
424 425
      else
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
426 427
	select= new SQL_SELECT;
	select->head=table;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
428
      }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
429 430 431 432
      if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
	error=1; /* purecov: inspected */
      select->file=tempfile;			// Read row ptrs from this file
      if (error >= 0)
433
	goto err;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434 435
    }
    if (table->key_read)
436
      table->restore_column_maps_after_mark_index();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
437 438
  }

439
  if (ignore)
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
440
    table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
441 442
  
  if (select && select->quick && select->quick->reset())
443
    goto err;
444
  table->file->try_semi_consistent_read(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
445 446
  init_read_record(&info,thd,table,select,0,1);

447
  updated= found= 0;
448
  thd->count_cuted_fields= CHECK_FIELD_WARN;		/* calc cuted fields */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
449
  thd->cuted_fields=0L;
450
  thd->proc_info="Updating";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
451

452
  transactional_table= table->file->has_transactions();
453
  thd->no_trans_update.stmt= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
454
  thd->abort_on_warning= test(!ignore &&
455 456 457
                              (thd->variables.sql_mode &
                               (MODE_STRICT_TRANS_TABLES |
                                MODE_STRICT_ALL_TABLES)));
458 459 460
  if (table->triggers &&
      table->triggers->has_triggers(TRG_EVENT_UPDATE,
                                    TRG_ACTION_AFTER))
461
  {
462 463 464 465 466 467 468
    /*
      The table has AFTER UPDATE triggers that might access to subject 
      table and therefore might need update to be done immediately. 
      So we turn-off the batching.
    */ 
    (void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
    will_batch= FALSE;
469
  }
470 471
  else
    will_batch= !table->file->start_bulk_update();
472

473 474 475 476 477 478 479 480
  /*
    We can use compare_record() to optimize away updates if
    the table handler is returning all columns OR if
    if all updated columns are read
  */
  can_compare_record= (!(table->file->ha_table_flags() &
                         HA_PARTIAL_COLUMN_READ) ||
                       bitmap_is_subset(table->write_set, table->read_set));
481

bk@work.mysql.com's avatar
bk@work.mysql.com committed
482 483
  while (!(error=info.read_record(&info)) && !thd->killed)
  {
484
    if (!(select && select->skip_record()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
485
    {
486
      if (table->file->was_semi_consistent_read())
487
        continue;  /* repeat the read of the same row if it still exists */
488

489
      store_record(table,record[1]);
490 491 492
      if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
                                               table->triggers,
                                               TRG_EVENT_UPDATE))
493
        break; /* purecov: inspected */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
494

bk@work.mysql.com's avatar
bk@work.mysql.com committed
495
      found++;
496

497
      if (!can_compare_record || compare_record(table))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
498
      {
monty@mysql.com's avatar
monty@mysql.com committed
499
        if ((res= table_list->view_check_option(thd, ignore)) !=
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
500 501 502 503 504 505 506 507 508 509 510
            VIEW_CHECK_OK)
        {
          found--;
          if (res == VIEW_CHECK_SKIP)
            continue;
          else if (res == VIEW_CHECK_ERROR)
          {
            error= 1;
            break;
          }
        }
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
        if (will_batch)
        {
          /*
            Typically a batched handler can execute the batched jobs when:
            1) When specifically told to do so
            2) When it is not a good idea to batch anymore
            3) When it is necessary to send batch for other reasons
               (One such reason is when READ's must be performed)

            1) is covered by exec_bulk_update calls.
            2) and 3) is handled by the bulk_update_row method.
            
            bulk_update_row can execute the updates including the one
            defined in the bulk_update_row or not including the row
            in the call. This is up to the handler implementation and can
            vary from call to call.

            The dup_key_found reports the number of duplicate keys found
            in those updates actually executed. It only reports those if
            the extra call with HA_EXTRA_IGNORE_DUP_KEY have been issued.
            If this hasn't been issued it returns an error code and can
            ignore this number. Thus any handler that implements batching
            for UPDATE IGNORE must also handle this extra call properly.

            If a duplicate key is found on the record included in this
            call then it should be included in the count of dup_key_found
            and error should be set to 0 (only if these errors are ignored).
          */
539 540
          error= table->file->bulk_update_row(table->record[1],
                                              table->record[0],
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
541
                                              &dup_key_found);
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
542
          limit+= dup_key_found;
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
543
          updated-= dup_key_found;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
544 545 546 547
        }
        else
        {
          /* Non-batched update */
548 549
	  error= table->file->ha_update_row(table->record[1],
                                            table->record[0]);
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
550 551
        }
        if (!error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
552 553
	{
	  updated++;
554
          thd->no_trans_update.stmt= !transactional_table;
555 556 557 558 559 560 561 562

          if (table->triggers &&
              table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                                TRG_ACTION_AFTER, TRUE))
          {
            error= 1;
            break;
          }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
563
	}
564
 	else if (!ignore ||
565
                 table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
566
	{
567
          /*
568
            If (ignore && error is ignorable) we don't have to
569 570
            do anything; otherwise...
          */
571
          if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
572
            thd->fatal_error(); /* Other handler errors are fatal */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
573 574 575 576 577
	  table->file->print_error(error,MYF(0));
	  error= 1;
	  break;
	}
      }
578

monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
579 580
      if (!--limit && using_limit)
      {
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
        /*
          We have reached end-of-file in most common situations where no
          batching has occurred and if batching was supposed to occur but
          no updates were made and finally when the batch execution was
          performed without error and without finding any duplicate keys.
          If the batched updates were performed with errors we need to
          check and if no error but duplicate key's found we need to
          continue since those are not counted for in limit.
        */
        if (will_batch &&
            ((error= table->file->exec_bulk_update(&dup_key_found)) ||
            !dup_key_found))
        {
 	  if (error)
          {
            /*
              The handler should not report error of duplicate keys if they
              are ignored. This is a requirement on batching handlers.
            */
            table->file->print_error(error,MYF(0));
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
601
            error= 1;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
602 603 604 605 606 607 608
            break;
          }
          /*
            Either an error was found and we are ignoring errors or there
            were duplicate keys found. In both cases we need to correct
            the counters and continue the loop.
          */
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
609 610
          limit= dup_key_found; //limit is 0 when we get here so need to +
          updated-= dup_key_found;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
611 612 613 614 615 616
        }
        else
        {
	  error= -1;				// Simulate end of file
	  break;
        }
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
617
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
618
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
619 620
    else
      table->file->unlock_row();
621
    thd->row_count++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
622
  }
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
623
  dup_key_found= 0;
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654

  /*
    todo bug#27571: to avoid asynchronization of `error' and
    `error_code' of binlog event constructor

    The concept, which is a bit different for insert(!), is to
    replace `error' assignment with the following lines

       killed_status= thd->killed; // get the status of the volatile 
    
    Notice: thd->killed is type of "state" whereas the lhs has
    "status" the suffix which translates according to WordNet: a state
    at a particular time - at the time of the end of per-row loop in
    our case. Binlogging ops are conducted with the status.

       error= (killed_status == THD::NOT_KILLED)?  error : 1;
    
    which applies to most mysql_$query functions.
    Event's constructor will accept `killed_status' as an argument:
    
       Query_log_event qinfo(..., killed_status);
    
    thd->killed might be changed after killed_status had got cached and this
    won't affect binlogging event but other effects remain.

    Open issue: In a case the error happened not because of KILLED -
    and then KILLED was caught later still within the loop - we shall
    do something to avoid binlogging of incorrect ER_SERVER_SHUTDOWN
    error_code.
  */

655 656
  if (thd->killed && !error)
    error= 1;					// Aborted
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
657 658 659 660 661 662 663 664 665 666 667 668 669
  else if (will_batch &&
           (loc_error= table->file->exec_bulk_update(&dup_key_found)))
    /*
      An error has occurred when a batched update was performed and returned
      an error indication. It cannot be an allowed duplicate key error since
      we require the batching handler to treat this as a normal behavior.

      Otherwise we simply remove the number of duplicate keys records found
      in the batched update.
    */
  {
    thd->fatal_error();
    table->file->print_error(loc_error,MYF(0));
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
670
    error= 1;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
671 672
  }
  else
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
673
    updated-= dup_key_found;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
674 675
  if (will_batch)
    table->file->end_bulk_update();
676
  table->file->try_semi_consistent_read(0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
677
  end_read_record(&info);
678
  delete select;
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
679
  thd->proc_info= "end";
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
680
  VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
681 682 683 684 685 686

  /*
    Invalidate the table in the query cache if something changed.
    This must be before binlog writing and ha_autocommit_...
  */
  if (updated)
monty@mysql.com's avatar
monty@mysql.com committed
687
  {
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
688
    query_cache_invalidate3(thd, table_list, 1);
monty@mysql.com's avatar
monty@mysql.com committed
689
  }
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
690

691 692 693 694 695 696 697 698 699 700
  /*
    error < 0 means really no error at all: we processed all rows until the
    last one without error. error > 0 means an error (e.g. unique key
    violation and no IGNORE or REPLACE). error == 0 is also an error (if
    preparing the record or invoking before triggers fails). See
    ha_autocommit_or_rollback(error>=0) and DBUG_RETURN(error>=0) below.
    Sometimes we want to binlog even if we updated no rows, in case user used
    it to be sure master and slave are in same state.
  */
  if ((error < 0) || (updated && !transactional_table))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
701
  {
702 703
    if (mysql_bin_log.is_open())
    {
704
      if (error < 0)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
705
        thd->clear_error();
706 707 708 709 710
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
                            transactional_table, FALSE) &&
          transactional_table)
      {
711
        error=1;				// Rollback update
712
      }
713
    }
714
    if (!transactional_table)
715
      thd->no_trans_update.all= TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
716
  }
717
  free_underlaid_joins(thd, select_lex);
718 719 720 721 722
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd, error >= 0))
      error=1;
  }
723

724 725 726 727 728 729
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }

730 731 732 733
  /* If LAST_INSERT_ID(X) was used, report X */
  id= thd->arg_of_last_insert_id_function ?
    thd->first_successful_insert_id_in_prev_stmt : 0;

734
  if (error < 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
735
  {
736
    char buff[STRING_BUFFER_USUAL_SIZE];
737 738
    sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
	    (ulong) thd->cuted_fields);
739 740
    thd->row_count_func=
      (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
741
    send_ok(thd, (ulong) thd->row_count_func, id, buff);
742
    DBUG_PRINT("info",("%ld records updated", (long) updated));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
743
  }
744
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;		/* calc cuted fields */
745
  thd->abort_on_warning= 0;
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
746
  DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
747 748 749

err:
  delete select;
750
  free_underlaid_joins(thd, select_lex);
751 752 753 754 755
  if (table->key_read)
  {
    table->key_read=0;
    table->file->extra(HA_EXTRA_NO_KEYREAD);
  }
756
  thd->abort_on_warning= 0;
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
757
  DBUG_RETURN(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
758
}
759

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
760 761 762 763 764 765
/*
  Prepare items in UPDATE statement

  SYNOPSIS
    mysql_prepare_update()
    thd			- thread handler
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
766
    table_list		- global/local table list
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
767 768 769 770 771
    conds		- conditions
    order_num		- number of ORDER BY list entries
    order		- ORDER BY clause list

  RETURN VALUE
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
772 773
    FALSE OK
    TRUE  error
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
774
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
775
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
776 777
			 Item **conds, uint order_num, ORDER *order)
{
778
  Item *fake_conds= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
779 780 781
  TABLE *table= table_list->table;
  TABLE_LIST tables;
  List<Item> all_fields;
782
  SELECT_LEX *select_lex= &thd->lex->select_lex;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
783 784 785
  DBUG_ENTER("mysql_prepare_update");

#ifndef NO_EMBEDDED_ACCESS_CHECKS
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
786 787
  table_list->grant.want_privilege= table->grant.want_privilege= 
    (SELECT_ACL & ~table->grant.privilege);
788
  table_list->register_want_access(SELECT_ACL);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
789 790 791 792 793
#endif

  bzero((char*) &tables,sizeof(tables));	// For ORDER BY
  tables.table= table;
  tables.alias= table_list->alias;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
794
  thd->lex->allow_sum_func= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
795

796 797
  if (setup_tables_and_check_access(thd, &select_lex->context, 
                                    &select_lex->top_join_list,
798
                                    table_list,
799
                                    &select_lex->leaf_tables,
800
                                    FALSE, UPDATE_ACL, SELECT_ACL) ||
801
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
802 803
      select_lex->setup_ref_array(thd, order_num) ||
      setup_order(thd, select_lex->ref_pointer_array,
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
804
		  table_list, all_fields, all_fields, order) ||
805
      setup_ftfuncs(select_lex))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
806
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
807 808 809

  /* Check that we are not using table that we are updating in a sub select */
  {
810
    TABLE_LIST *duplicate;
811
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
812 813 814 815 816
    {
      update_non_unique_table_error(table_list, "UPDATE", duplicate);
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
      DBUG_RETURN(TRUE);
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
817
  }
818
  select_lex->fix_prepare_information(thd, conds, &fake_conds);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
819
  DBUG_RETURN(FALSE);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
820 821
}

822

823
/***************************************************************************
824
  Update multiple tables from join 
825 826
***************************************************************************/

827
/*
828
  Get table map for list of Item_field
829 830
*/

831 832 833 834 835 836 837 838
static table_map get_table_map(List<Item> *items)
{
  List_iterator_fast<Item> item_it(*items);
  Item_field *item;
  table_map map= 0;

  while ((item= (Item_field *) item_it++)) 
    map|= item->used_tables();
839
  DBUG_PRINT("info", ("table_map: 0x%08lx", (long) map));
840 841 842 843
  return map;
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
844 845
/*
  make update specific preparation and checks after opening tables
846

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
847 848 849
  SYNOPSIS
    mysql_multi_update_prepare()
    thd         thread handler
850

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
851
  RETURN
852 853
    FALSE OK
    TRUE  Error
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
854
*/
855

856
bool mysql_multi_update_prepare(THD *thd)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
857 858 859
{
  LEX *lex= thd->lex;
  TABLE_LIST *table_list= lex->query_tables;
monty@mysql.com's avatar
monty@mysql.com committed
860
  TABLE_LIST *tl, *leaves;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
861
  List<Item> *fields= &lex->select_lex.item_list;
862
  table_map tables_for_update;
863
  bool update_view= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
864 865 866 867 868 869
  /*
    if this multi-update was converted from usual update, here is table
    counter else junk will be assigned here, but then replaced with real
    count in open_tables()
  */
  uint  table_count= lex->table_count;
870
  const bool using_lock_tables= thd->locked_tables != 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
871
  bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
872
  bool need_reopen= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
873 874
  DBUG_ENTER("mysql_multi_update_prepare");

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
875 876
  /* following need for prepared statements, to run next time multi-update */
  thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
877

878 879
reopen_tables:

880
  /* open tables and create derived ones, but do not lock and fill them */
881
  if (((original_multiupdate || need_reopen) &&
882
       open_tables(thd, &table_list, &table_count, 0)) ||
883
      mysql_handle_derived(lex, &mysql_derived_prepare))
884
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
885 886 887 888 889
  /*
    setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
    second time, but this call will do nothing (there are check for second
    call in setup_tables()).
  */
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
890

891 892
  if (setup_tables_and_check_access(thd, &lex->select_lex.context,
                                    &lex->select_lex.top_join_list,
893
                                    table_list,
894
                                    &lex->select_lex.leaf_tables, FALSE,
895
                                    UPDATE_ACL, SELECT_ACL))
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
896
    DBUG_RETURN(TRUE);
897

898
  if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
899
    DBUG_RETURN(TRUE);
900 901 902 903 904 905 906 907 908 909 910

  for (tl= table_list; tl ; tl= tl->next_local)
  {
    if (tl->view)
    {
      update_view= 1;
      break;
    }
  }

  if (update_view && check_fields(thd, *fields))
911
  {
912
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
913 914
  }

915
  tables_for_update= get_table_map(fields);
916 917

  /*
918
    Setup timestamp handling and locking mode
919
  */
920
  leaves= lex->select_lex.leaf_tables;
921
  for (tl= leaves; tl; tl= tl->next_leaf)
922
  {
923
    TABLE *table= tl->table;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
924
    /* Only set timestamp column if this is not modified */
925
    if (table->timestamp_field &&
926 927
        bitmap_is_set(table->write_set,
                      table->timestamp_field->field_index))
monty@mysql.com's avatar
monty@mysql.com committed
928
      table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
929

930 931
    /* if table will be updated then check that it is unique */
    if (table->map & tables_for_update)
932
    {
933
      if (!tl->updatable || check_key_in_view(thd, tl))
934
      {
935
        my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
936
        DBUG_RETURN(TRUE);
937
      }
938

939
      table->mark_columns_needed_for_update();
940
      DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
941 942 943 944
      /*
        If table will be updated we should not downgrade lock for it and
        leave it as is.
      */
monty@mysql.com's avatar
monty@mysql.com committed
945
    }
946 947 948
    else
    {
      DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
monty@mysql.com's avatar
monty@mysql.com committed
949 950 951 952 953 954
      /*
        If we are using the binary log, we need TL_READ_NO_INSERT to get
        correct order of statements. Otherwise, we use a TL_READ lock to
        improve performance.
      */
      tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
955
      tl->updating= 0;
956
      /* Update TABLE::lock_type accordingly. */
957
      if (!tl->placeholder() && !using_lock_tables)
958
        tl->table->reginfo.lock_type= tl->lock_type;
959
    }
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
960
  }
961
  for (tl= table_list; tl; tl= tl->next_local)
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
962
  {
monty@mishka.local's avatar
monty@mishka.local committed
963
    /* Check access privileges for table */
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
964
    if (!tl->derived)
965
    {
monty@mysql.com's avatar
monty@mysql.com committed
966 967
      uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL;
      if (check_access(thd, want_privilege,
968 969
                       tl->db, &tl->grant.privilege, 0, 0, 
                       test(tl->schema_table)) ||
970
          check_grant(thd, want_privilege, tl, 0, 1, 0))
monty@mishka.local's avatar
monty@mishka.local committed
971
        DBUG_RETURN(TRUE);
972
    }
973
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
974

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
975 976 977
  /* check single table update for view compound from several tables */
  for (tl= table_list; tl; tl= tl->next_local)
  {
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
978
    if (tl->effective_algorithm == VIEW_ALGORITHM_MERGE)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
979 980
    {
      TABLE_LIST *for_update= 0;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
981
      if (tl->check_single_table(&for_update, tables_for_update, tl))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
982 983 984 985 986 987 988 989
      {
	my_error(ER_VIEW_MULTIUPDATE, MYF(0),
		 tl->view_db.str, tl->view_name.str);
	DBUG_RETURN(-1);
      }
    }
  }

990
  /* now lock and fill tables */
991
  if (lock_tables(thd, table_list, table_count, &need_reopen))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
992
  {
993 994 995
    if (!need_reopen)
      DBUG_RETURN(TRUE);

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
996
    /*
997 998 999 1000
      We have to reopen tables since some of them were altered or dropped
      during lock_tables() or something was done with their triggers.
      Let us do some cleanups to be able do setup_table() and setup_fields()
      once again.
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1001 1002 1003
    */
    List_iterator_fast<Item> it(*fields);
    Item *item;
monty@mysql.com's avatar
monty@mysql.com committed
1004
    while ((item= it++))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1005 1006
      item->cleanup();

monty@mysql.com's avatar
monty@mysql.com committed
1007
    /* We have to cleanup translation tables of views. */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1008 1009 1010
    for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
      tbl->cleanup_items();

1011
    close_tables_for_reopen(thd, &table_list);
1012
    goto reopen_tables;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1013
  }
monty@mysql.com's avatar
monty@mysql.com committed
1014

1015 1016 1017 1018 1019
  /*
    Check that we are not using table that we are updating, but we should
    skip all tables of UPDATE SELECT itself
  */
  lex->select_lex.exclude_from_table_unique_test= TRUE;
monty@mysql.com's avatar
monty@mysql.com committed
1020 1021 1022 1023 1024
  /* We only need SELECT privilege for columns in the values list */
  for (tl= leaves; tl; tl= tl->next_leaf)
  {
    TABLE *table= tl->table;
    TABLE_LIST *tlist;
1025
    if (!(tlist= tl->top_table())->derived)
monty@mysql.com's avatar
monty@mysql.com committed
1026 1027 1028 1029 1030 1031 1032
    {
      tlist->grant.want_privilege=
        (SELECT_ACL & ~tlist->grant.privilege);
      table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
    }
    DBUG_PRINT("info", ("table: %s  want_privilege: %u", tl->alias,
                        (uint) table->grant.want_privilege));
1033
    if (tl->lock_type != TL_READ &&
1034
        tl->lock_type != TL_READ_NO_INSERT)
1035
    {
1036
      TABLE_LIST *duplicate;
1037
      if ((duplicate= unique_table(thd, tl, table_list, 0)))
1038 1039 1040 1041
      {
        update_non_unique_table_error(table_list, "UPDATE", duplicate);
        DBUG_RETURN(TRUE);
      }
1042
    }
monty@mysql.com's avatar
monty@mysql.com committed
1043
  }
svoj@may.pils.ru's avatar
svoj@may.pils.ru committed
1044 1045 1046 1047 1048 1049
  /*
    Set exclude_from_table_unique_test value back to FALSE. It is needed for
    further check in multi_update::prepare whether to use record cache.
  */
  lex->select_lex.exclude_from_table_unique_test= FALSE;
 
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1050 1051
  if (thd->fill_derived_tables() &&
      mysql_handle_derived(lex, &mysql_derived_filling))
1052
    DBUG_RETURN(TRUE);
1053

bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1054
  DBUG_RETURN (FALSE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1055 1056 1057
}


monty@mysql.com's avatar
monty@mysql.com committed
1058 1059 1060
/*
  Setup multi-update handling and call SELECT to do the join
*/
1061

1062 1063 1064 1065 1066
bool mysql_multi_update(THD *thd,
                        TABLE_LIST *table_list,
                        List<Item> *fields,
                        List<Item> *values,
                        COND *conds,
1067
                        ulonglong options,
1068
                        enum enum_duplicates handle_duplicates, bool ignore,
1069
                        SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1070 1071 1072 1073
{
  multi_update *result;
  DBUG_ENTER("mysql_multi_update");

1074
  if (!(result= new multi_update(table_list,
1075 1076
				 thd->lex->select_lex.leaf_tables,
				 fields, values,
1077
				 handle_duplicates, ignore)))
1078
    DBUG_RETURN(TRUE);
1079

1080
  thd->no_trans_update.stmt= FALSE;
1081 1082 1083 1084
  thd->abort_on_warning= test(thd->variables.sql_mode &
                              (MODE_STRICT_TRANS_TABLES |
                               MODE_STRICT_ALL_TABLES));

1085
  List<Item> total_list;
1086 1087 1088 1089 1090 1091 1092 1093
  (void) mysql_select(thd, &select_lex->ref_pointer_array,
                      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 |
                      OPTION_SETUP_TABLES_DONE,
                      result, unit, select_lex);
1094
  delete result;
1095
  thd->abort_on_warning= 0;
1096
  DBUG_RETURN(FALSE);
1097 1098
}

1099

1100
multi_update::multi_update(TABLE_LIST *table_list,
1101
			   TABLE_LIST *leaves_list,
1102
			   List<Item> *field_list, List<Item> *value_list,
monty@mysql.com's avatar
monty@mysql.com committed
1103 1104
			   enum enum_duplicates handle_duplicates_arg,
                           bool ignore_arg)
1105
  :all_tables(table_list), leaves(leaves_list), update_tables(0),
1106
   tmp_tables(0), updated(0), found(0), fields(field_list),
1107 1108
   values(value_list), table_count(0), copy_field(0),
   handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
1109
   transactional_tables(1), ignore(ignore_arg)
1110 1111 1112 1113 1114 1115 1116
{}


/*
  Connect fields with tables and create list of tables that are updated
*/

1117 1118
int multi_update::prepare(List<Item> &not_used_values,
			  SELECT_LEX_UNIT *lex_unit)
1119
{
1120 1121
  TABLE_LIST *table_ref;
  SQL_LIST update;
1122
  table_map tables_to_update;
1123 1124 1125 1126
  Item_field *item;
  List_iterator_fast<Item> field_it(*fields);
  List_iterator_fast<Item> value_it(*values);
  uint i, max_fields;
1127
  DBUG_ENTER("multi_update::prepare");
1128

1129
  thd->count_cuted_fields= CHECK_FIELD_WARN;
1130
  thd->cuted_fields=0L;
1131 1132
  thd->proc_info="updating main table";

1133
  tables_to_update= get_table_map(fields);
1134

1135
  if (!tables_to_update)
1136
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1137
    my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
1138
    DBUG_RETURN(1);
1139
  }
1140

1141
  /*
1142
    We have to check values after setup_tables to get covering_keys right in
1143
    reference tables
1144
  */
1145

1146
  if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
1147 1148
    DBUG_RETURN(1);

1149
  /*
1150 1151 1152
    Save tables beeing updated in update_tables
    update_table->shared is position for table
    Don't use key read on tables that are updated
1153
  */
1154 1155

  update.empty();
1156
  for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
1157
  {
1158
    /* TODO: add support of view of join support */
1159 1160
    TABLE *table=table_ref->table;
    if (tables_to_update & table->map)
1161
    {
1162 1163 1164
      TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
						sizeof(*tl));
      if (!tl)
1165
	DBUG_RETURN(1);
1166
      update.link_in_list((uchar*) tl, (uchar**) &tl->next_local);
1167 1168
      tl->shared= table_count++;
      table->no_keyread=1;
1169
      table->covering_keys.clear_all();
1170
      table->pos_in_table_list= tl;
1171 1172 1173
      if (table->triggers &&
          table->triggers->has_triggers(TRG_EVENT_UPDATE,
                                        TRG_ACTION_AFTER))
1174
      {
1175 1176 1177 1178 1179 1180
	/*
           The table has AFTER UPDATE triggers that might access to subject 
           table and therefore might need update to be done immediately. 
           So we turn-off the batching.
	*/ 
	(void) table->file->extra(HA_EXTRA_UPDATE_CANNOT_BATCH);
1181
      }
1182 1183
    }
  }
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1184 1185


1186 1187 1188
  table_count=  update.elements;
  update_tables= (TABLE_LIST*) update.first;

1189
  tmp_tables = (TABLE**) thd->calloc(sizeof(TABLE *) * table_count);
1190 1191 1192 1193 1194 1195
  tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) *
						   table_count);
  fields_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
					      table_count);
  values_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
					      table_count);
1196
  if (thd->is_fatal_error)
1197 1198 1199 1200 1201 1202
    DBUG_RETURN(1);
  for (i=0 ; i < table_count ; i++)
  {
    fields_for_table[i]= new List_item;
    values_for_table[i]= new List_item;
  }
1203
  if (thd->is_fatal_error)
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
    DBUG_RETURN(1);

  /* Split fields into fields_for_table[] and values_by_table[] */

  while ((item= (Item_field *) field_it++))
  {
    Item *value= value_it++;
    uint offset= item->field->table->pos_in_table_list->shared;
    fields_for_table[offset]->push_back(item);
    values_for_table[offset]->push_back(value);
  }
1215
  if (thd->is_fatal_error)
1216 1217 1218 1219 1220 1221 1222
    DBUG_RETURN(1);

  /* Allocate copy fields */
  max_fields=0;
  for (i=0 ; i < table_count ; i++)
    set_if_bigger(max_fields, fields_for_table[i]->elements);
  copy_field= new Copy_field[max_fields];
1223 1224
  DBUG_RETURN(thd->is_fatal_error != 0);
}
1225 1226


1227 1228
/*
  Check if table is safe to update on fly
1229

1230 1231 1232 1233 1234
  SYNOPSIS
    safe_update_on_fly()
    thd                 Thread handler
    join_tab            How table is used in join
    all_tables          List of tables
1235

1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
  NOTES
    We can update the first table in join on the fly if we know that
    a row in this table will never be read twice. This is true under
    the following conditions:

    - We are doing a table scan and the data is in a separate file (MyISAM) or
      if we don't update a clustered key.

    - We are doing a range scan and we don't update the scan key or
      the primary key for a clustered table handler.

    - Table is not joined to itself.

1249 1250
    This function gets information about fields to be updated from
    the TABLE::write_set bitmap.
1251

1252 1253 1254 1255 1256 1257 1258 1259 1260
  WARNING
    This code is a bit dependent of how make_join_readinfo() works.

  RETURN
    0		Not safe to update
    1		Safe to update
*/

static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab,
1261
                               TABLE_LIST *table_ref, TABLE_LIST *all_tables)
1262 1263
{
  TABLE *table= join_tab->table;
1264
  if (unique_table(thd, table_ref, all_tables, 0))
1265 1266 1267 1268 1269
    return 0;
  switch (join_tab->type) {
  case JT_SYSTEM:
  case JT_CONST:
  case JT_EQ_REF:
1270
    return TRUE;				// At most one matching row
1271
  case JT_REF:
1272
  case JT_REF_OR_NULL:
1273
    return !is_key_used(table, join_tab->ref.key, table->write_set);
1274 1275 1276
  case JT_ALL:
    /* If range search on index */
    if (join_tab->quick)
1277
      return !join_tab->quick->is_keys_used(table->write_set);
1278
    /* If scanning in clustered key */
1279
    if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
1280
	table->s->primary_key < MAX_KEY)
1281
      return !is_key_used(table, table->s->primary_key, table->write_set);
1282
    return TRUE;
1283 1284
  default:
    break;					// Avoid compler warning
1285
  }
1286
  return FALSE;
1287

1288 1289 1290
}


1291
/*
1292
  Initialize table for multi table
1293

1294 1295 1296 1297
  IMPLEMENTATION
    - Update first table in join on the fly, if possible
    - Create temporary tables to store changed values for all other tables
      that are updated (and main_table if the above doesn't hold).
1298 1299 1300
*/

bool
1301 1302
multi_update::initialize_tables(JOIN *join)
{
1303 1304 1305 1306 1307 1308 1309
  TABLE_LIST *table_ref;
  DBUG_ENTER("initialize_tables");

  if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
    DBUG_RETURN(1);
  main_table=join->join_tab->table;
  trans_safe= transactional_tables= main_table->file->has_transactions();
1310 1311 1312
  table_to_update= 0;

  /* Create a temporary table for keys to all tables, except main table */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1313
  for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
1314
  {
1315
    TABLE *table=table_ref->table;
1316
    uint cnt= table_ref->shared;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1317
    Item_field *ifield;
1318 1319
    List<Item> temp_fields= *fields_for_table[cnt];
    ORDER     group;
1320
    TMP_TABLE_PARAM *tmp_param;
1321

1322
    table->mark_columns_needed_for_update();
1323 1324
    if (ignore)
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1325 1326
    if (table == main_table)			// First table in join
    {
1327
      if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables))
1328 1329 1330 1331
      {
	table_to_update= main_table;		// Update table on the fly
	continue;
      }
1332
    }
1333
    table->prepare_for_position();
1334

1335
    tmp_param= tmp_table_param+cnt;
1336 1337 1338 1339 1340 1341 1342 1343
    /*
      Create a temporary table to store all fields that are changed for this
      table. The first field in the temporary table is a pointer to the
      original row so that we can find and update it
    */

    /* ok to be on stack as this is not referenced outside of this func */
    Field_string offset(table->file->ref_length, 0, "offset",
1344 1345
			&my_charset_bin);
    offset.init(table);
1346 1347 1348 1349 1350
    /*
      The field will be converted to varstring when creating tmp table if
      table to be updated was created by mysql 4.1. Deny this.
    */
    offset.can_alter_field_type= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1351
    if (!(ifield= new Item_field(((Field *) &offset))))
Sinisa@sinisa.nasamreza.org's avatar
Sinisa@sinisa.nasamreza.org committed
1352
      DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1353 1354
    ifield->maybe_null= 0;
    if (temp_fields.push_front(ifield))
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
      DBUG_RETURN(1);

    /* Make an unique key over the first field to avoid duplicated updates */
    bzero((char*) &group, sizeof(group));
    group.asc= 1;
    group.item= (Item**) temp_fields.head_ref();

    tmp_param->quick_group=1;
    tmp_param->field_count=temp_fields.elements;
    tmp_param->group_parts=1;
    tmp_param->group_length= table->file->ref_length;
    if (!(tmp_tables[cnt]=create_tmp_table(thd,
					   tmp_param,
					   temp_fields,
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
1369 1370
					   (ORDER*) &group, 0, 0,
					   TMP_TABLE_ALL_COLUMNS,
1371 1372
					   HA_POS_ERROR,
					   (char *) "")))
1373 1374
      DBUG_RETURN(1);
    tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
1375
  }
1376
  DBUG_RETURN(0);
1377 1378 1379 1380 1381
}


multi_update::~multi_update()
{
1382
  TABLE_LIST *table;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1383
  for (table= update_tables ; table; table= table->next_local)
1384
  {
1385
    table->table->no_keyread= table->table->no_cache= 0;
1386 1387 1388
    if (ignore)
      table->table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
  }
1389

1390 1391
  if (tmp_tables)
  {
1392 1393 1394 1395 1396 1397 1398 1399
    for (uint cnt = 0; cnt < table_count; cnt++)
    {
      if (tmp_tables[cnt])
      {
	free_tmp_table(thd, tmp_tables[cnt]);
	tmp_table_param[cnt].cleanup();
      }
    }
1400
  }
1401 1402
  if (copy_field)
    delete [] copy_field;
1403
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;		// Restore this setting
1404
  if (!trans_safe)
1405
    thd->no_trans_update.all= TRUE;
1406 1407 1408
}


1409
bool multi_update::send_data(List<Item> &not_used_values)
1410
{
1411 1412 1413
  TABLE_LIST *cur_table;
  DBUG_ENTER("multi_update::send_data");

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1414
  for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
1415
  {
1416
    TABLE *table= cur_table->table;
1417
    uint offset= cur_table->shared;
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
    /*
      Check if we are using outer join and we didn't find the row
      or if we have already updated this row in the previous call to this
      function.

      The same row may be presented here several times in a join of type
      UPDATE t1 FROM t1,t2 SET t1.a=t2.a

      In this case we will do the update for the first found row combination.
      The join algorithm guarantees that we will not find the a row in
      t1 several times.
    */
1430 1431 1432
    if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
      continue;

1433 1434 1435 1436 1437
    /*
      We can use compare_record() to optimize away updates if
      the table handler is returning all columns OR if
      if all updated columns are read
    */
1438
    if (table == table_to_update)
1439
    {
1440 1441 1442 1443 1444
      bool can_compare_record;
      can_compare_record= (!(table->file->ha_table_flags() &
                             HA_PARTIAL_COLUMN_READ) ||
                           bitmap_is_subset(table->write_set,
                                            table->read_set));
1445
      table->status|= STATUS_UPDATED;
1446
      store_record(table,record[1]);
1447 1448 1449 1450
      if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
                                               *values_for_table[offset], 0,
                                               table->triggers,
                                               TRG_EVENT_UPDATE))
1451
	DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1452

1453
      found++;
1454
      if (!can_compare_record || compare_record(table))
1455
      {
1456
	int error;
monty@mysql.com's avatar
monty@mysql.com committed
1457
        if ((error= cur_table->view_check_option(thd, ignore)) !=
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1458 1459 1460 1461 1462 1463 1464 1465
            VIEW_CHECK_OK)
        {
          found--;
          if (error == VIEW_CHECK_SKIP)
            continue;
          else if (error == VIEW_CHECK_ERROR)
            DBUG_RETURN(1);
        }
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
        if (!updated++)
        {
          /*
            Inform the main table that we are going to update the table even
            while we may be scanning it.  This will flush the read cache
            if it's used.
          */
          main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
        }
        if ((error=table->file->ha_update_row(table->record[1],
                                              table->record[0])))
        {
          updated--;
1479
          if (!ignore ||
1480
              table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
1481
          {
1482
            /*
1483
              If (ignore && error == is ignorable) we don't have to
1484 1485
              do anything; otherwise...
            */
1486
            if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
1487
              thd->fatal_error(); /* Other handler errors are fatal */
1488 1489 1490 1491
            table->file->print_error(error,MYF(0));
            DBUG_RETURN(1);
          }
        }
1492 1493 1494
        else
        {
          if (!table->file->has_transactions())
1495
            thd->no_trans_update.stmt= TRUE;
1496 1497 1498
          if (table->triggers &&
              table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                                TRG_ACTION_AFTER, TRUE))
1499
            DBUG_RETURN(1);
1500
        }
1501
      }
1502 1503 1504 1505 1506
    }
    else
    {
      int error;
      TABLE *tmp_table= tmp_tables[offset];
1507
      table->file->position(table->record[0]);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1508
      fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
1509 1510 1511 1512
      /* Store pointer to row */
      memcpy((char*) tmp_table->field[0]->ptr,
	     (char*) table->file->ref, table->file->ref_length);
      /* Write row, ignoring duplicated updates to a row */
1513
      error= tmp_table->file->ha_write_row(tmp_table->record[0]);
1514
      if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
1515
      {
1516
        if (error &&
1517
            create_myisam_from_heap(thd, tmp_table,
1518 1519 1520 1521 1522
                                    tmp_table_param + offset, error, 1))
        {
          do_update= 0;
          DBUG_RETURN(1);			// Not a table_is_full error
        }
1523
        found++;
1524
      }
1525 1526
    }
  }
1527
  DBUG_RETURN(0);
1528 1529
}

1530

1531 1532 1533
void multi_update::send_error(uint errcode,const char *err)
{
  /* First send error what ever it is ... */
1534
  my_error(errcode, MYF(0), err);
1535 1536 1537 1538

  /* If nothing updated return */
  if (!updated)
    return;
1539

1540
  /* Something already updated so we have to invalidate cache */
1541 1542
  query_cache_invalidate3(thd, update_tables, 1);

1543
  /*
1544 1545
    If all tables that has been updated are trans safe then just do rollback.
    If not attempt to do remaining updates.
1546
  */
1547 1548

  if (trans_safe)
1549
    ha_rollback_stmt(thd);
1550 1551 1552 1553 1554
  else if (do_update && table_count > 1)
  {
    /* Add warning here */
    VOID(do_updates(0));
  }
1555 1556 1557
}


1558
int multi_update::do_updates(bool from_send_error)
1559
{
1560 1561 1562
  TABLE_LIST *cur_table;
  int local_error;
  ha_rows org_updated;
1563
  TABLE *table, *tmp_table;
1564 1565
  DBUG_ENTER("do_updates");

1566
  do_update= 0;					// Don't retry this function
1567
  if (!found)
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1568
    DBUG_RETURN(0);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1569
  for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
1570
  {
1571
    uchar *ref_pos;
1572
    bool can_compare_record;
1573

1574
    table = cur_table->table;
1575
    if (table == table_to_update)
1576 1577
      continue;					// Already updated
    org_updated= updated;
1578
    tmp_table= tmp_tables[cur_table->shared];
1579
    tmp_table->file->extra(HA_EXTRA_CACHE);	// Change to read cache
1580
    (void) table->file->ha_rnd_init(0);
1581 1582 1583 1584 1585 1586 1587 1588 1589
    table->file->extra(HA_EXTRA_NO_CACHE);

    /*
      Setup copy functions to copy fields from temporary table
    */
    List_iterator_fast<Item> field_it(*fields_for_table[cur_table->shared]);
    Field **field= tmp_table->field+1;		// Skip row pointer
    Copy_field *copy_field_ptr= copy_field, *copy_field_end;
    for ( ; *field ; field++)
1590
    {
1591 1592
      Item_field *item= (Item_field* ) field_it++;
      (copy_field_ptr++)->set(item->field, *field, 0);
1593
    }
1594 1595
    copy_field_end=copy_field_ptr;

1596
    if ((local_error = tmp_table->file->ha_rnd_init(1)))
1597 1598
      goto err;

1599 1600 1601 1602 1603
    can_compare_record= (!(table->file->ha_table_flags() &
                           HA_PARTIAL_COLUMN_READ) ||
                         bitmap_is_subset(table->write_set,
                                          table->read_set));

1604
    ref_pos= tmp_table->field[0]->ptr;
1605
    for (;;)
1606
    {
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
      if (thd->killed && trans_safe)
	goto err;
      if ((local_error=tmp_table->file->rnd_next(tmp_table->record[0])))
      {
	if (local_error == HA_ERR_END_OF_FILE)
	  break;
	if (local_error == HA_ERR_RECORD_DELETED)
	  continue;				// May happen on dup key
	goto err;
      }
      if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
	goto err;
1619
      table->status|= STATUS_UPDATED;
1620
      store_record(table,record[1]);
1621 1622 1623 1624 1625 1626 1627

      /* Copy data from temporary table to current table */
      for (copy_field_ptr=copy_field;
	   copy_field_ptr != copy_field_end;
	   copy_field_ptr++)
	(*copy_field_ptr->do_copy)(copy_field_ptr);

1628 1629 1630 1631 1632
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                            TRG_ACTION_BEFORE, TRUE))
        goto err2;

1633
      if (!can_compare_record || compare_record(table))
1634
      {
igor@olga.mysql.com's avatar
igor@olga.mysql.com committed
1635 1636 1637 1638 1639 1640 1641 1642 1643
        int error;
        if ((error= cur_table->view_check_option(thd, ignore)) !=
            VIEW_CHECK_OK)
        {
          if (error == VIEW_CHECK_SKIP)
            continue;
          else if (error == VIEW_CHECK_ERROR)
            goto err;
        }
1644 1645
	if ((local_error=table->file->ha_update_row(table->record[1],
						    table->record[0])))
1646
	{
1647
	  if (!ignore ||
1648
              table->file->is_fatal_error(local_error, HA_CHECK_DUP_KEY))
1649 1650 1651
	    goto err;
	}
	updated++;
1652 1653 1654 1655 1656

        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                              TRG_ACTION_AFTER, TRUE))
          goto err2;
1657
      }
1658 1659 1660 1661 1662
    }

    if (updated != org_updated)
    {
      if (table->file->has_transactions())
1663
	transactional_tables= 1;
1664
      else
1665
	trans_safe= 0;				// Can't do safe rollback
1666
    }
1667 1668
    (void) table->file->ha_rnd_end();
    (void) tmp_table->file->ha_rnd_end();
1669
  }
1670 1671 1672 1673
  DBUG_RETURN(0);

err:
  if (!from_send_error)
monty@mysql.com's avatar
monty@mysql.com committed
1674 1675
  {
    thd->fatal_error();
1676
    table->file->print_error(local_error,MYF(0));
monty@mysql.com's avatar
monty@mysql.com committed
1677
  }
1678

1679
err2:
1680 1681 1682
  (void) table->file->ha_rnd_end();
  (void) tmp_table->file->ha_rnd_end();

1683 1684 1685
  if (updated != org_updated)
  {
    if (table->file->has_transactions())
1686
      transactional_tables= 1;
1687 1688 1689 1690
    else
      trans_safe= 0;
  }
  DBUG_RETURN(1);
1691 1692 1693
}


monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1694 1695
/* out: 1 if error, 0 if success */

1696 1697
bool multi_update::send_eof()
{
1698
  char buff[STRING_BUFFER_USUAL_SIZE];
1699
  ulonglong id;
1700
  thd->proc_info="updating reference tables";
1701 1702

  /* Does updates for the last n - 1 tables, returns 0 if ok */
1703
  int local_error = (table_count) ? do_updates(0) : 0;
1704
  thd->proc_info= "end";
1705

heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
1706 1707 1708 1709 1710 1711 1712 1713
  /* We must invalidate the query cache before binlog writing and
  ha_autocommit_... */

  if (updated)
  {
    query_cache_invalidate3(thd, update_tables, 1);
  }

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1714 1715
  /*
    Write the SQL statement to the binlog if we updated
1716
    rows and we succeeded or if we updated some non
1717
    transactional tables.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1718
  */
1719

1720
  if ((local_error == 0) || (updated && !trans_safe))
1721
  {
1722 1723
    if (mysql_bin_log.is_open())
    {
1724
      if (local_error == 0)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
1725
        thd->clear_error();
1726 1727 1728 1729 1730
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
                            transactional_tables, FALSE) &&
          trans_safe)
      {
1731
	local_error= 1;				// Rollback update
1732
      }
1733
    }
1734
    if (!transactional_tables)
1735
     thd->no_trans_update.all= TRUE;
1736
  }
1737

1738 1739
  if (transactional_tables)
  {
1740
    if (ha_autocommit_or_rollback(thd, local_error != 0))
1741 1742
      local_error=1;
  }
1743

1744 1745 1746 1747 1748
  if (local_error > 0) // if the above log write did not fail ...
  {
    /* 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));
1749
    return TRUE;
1750
  }
1751

1752 1753
  id= thd->arg_of_last_insert_id_function ?
    thd->first_successful_insert_id_in_prev_stmt : 0;
1754 1755
  sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
	  (ulong) thd->cuted_fields);
1756 1757
  thd->row_count_func=
    (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
1758
  ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
1759
  return FALSE;
1760
}