sql_update.cc 52.3 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000-2006 MySQL AB
2

unknown's avatar
unknown 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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6

unknown's avatar
unknown 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

unknown's avatar
unknown 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
*/
unknown's avatar
unknown committed
21 22

#include "mysql_priv.h"
23
#include "sql_select.h"
24 25
#include "sp_head.h"
#include "sql_trigger.h"
unknown's avatar
unknown committed
26 27 28

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

29
bool compare_record(TABLE *table, query_id_t query_id)
unknown's avatar
unknown committed
30
{
31
  if (table->s->blob_fields + table->s->varchar_fields == 0)
unknown's avatar
unknown committed
32
    return cmp_record(table,record[1]);
unknown's avatar
unknown committed
33
  /* Compare null bits */
unknown's avatar
unknown 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
unknown's avatar
unknown committed
38
  /* Compare updated fields */
unknown's avatar
unknown committed
39 40
  for (Field **ptr=table->field ; *ptr ; ptr++)
  {
41
    if ((*ptr)->query_id == query_id &&
42
	(*ptr)->cmp_binary_offset(table->s->rec_buff_length))
43
      return TRUE;
unknown's avatar
unknown committed
44
  }
45
  return FALSE;
unknown's avatar
unknown committed
46 47 48
}


unknown's avatar
VIEW  
unknown committed
49 50 51 52 53
/*
  check that all fields are real fields

  SYNOPSIS
    check_fields()
unknown's avatar
unknown committed
54
    thd             thread handler
unknown's avatar
VIEW  
unknown 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
*/

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

unknown's avatar
VIEW  
unknown committed
68 69
  while ((item= it++))
  {
70
    if (!(field= item->filed_for_view_update()))
unknown's avatar
VIEW  
unknown committed
71
    {
72
      /* item has name, because it comes from VIEW SELECT list */
73
      my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
unknown's avatar
VIEW  
unknown committed
74 75
      return TRUE;
    }
unknown's avatar
unknown committed
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
    */
unknown's avatar
unknown committed
80
    thd->change_item_tree(it.ref(), new Item_field(thd, field));
unknown's avatar
VIEW  
unknown 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
unknown's avatar
merge  
unknown 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,
unknown's avatar
unknown committed
113
		 ha_rows limit,
114
		 enum enum_duplicates handle_duplicates, bool ignore)
unknown's avatar
unknown committed
115
{
unknown's avatar
unknown committed
116
  bool		using_limit= limit != HA_POS_ERROR;
117
  bool		safe_update= test(thd->options & OPTION_SAFE_UPDATES);
unknown's avatar
unknown committed
118
  bool		used_key_is_modified, transactional_table;
119
  bool		can_compare_record;
unknown's avatar
unknown committed
120
  int           res;
unknown's avatar
unknown committed
121
  int		error;
122 123
  uint		used_index= MAX_KEY;
  bool          need_sort= TRUE;
124 125 126
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  uint		want_privilege;
#endif
unknown's avatar
unknown committed
127
  uint          table_count= 0;
128
  query_id_t	query_id=thd->query_id, timestamp_query_id;
129
  ha_rows	updated, found;
unknown's avatar
unknown committed
130 131
  key_map	old_used_keys;
  TABLE		*table;
unknown's avatar
unknown committed
132
  SQL_SELECT	*select;
unknown's avatar
unknown committed
133
  READ_RECORD	info;
134
  SELECT_LEX    *select_lex= &thd->lex->select_lex;
135
  bool need_reopen;
136
  List<Item> all_fields;
137
  THD::killed_state killed_status= THD::NOT_KILLED;
unknown's avatar
unknown committed
138
  DBUG_ENTER("mysql_update");
unknown's avatar
unknown committed
139

unknown's avatar
unknown committed
140
  LINT_INIT(timestamp_query_id);
unknown's avatar
unknown committed
141

142
  for ( ; ; )
143
  {
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    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);
160
    close_tables_for_reopen(thd, &table_list);
161
  }
unknown's avatar
unknown committed
162

163
  if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
unknown's avatar
unknown committed
164 165
      (thd->fill_derived_tables() &&
       mysql_handle_derived(thd->lex, &mysql_derived_filling)))
unknown's avatar
merge  
unknown committed
166
    DBUG_RETURN(1);
unknown's avatar
unknown committed
167

unknown's avatar
unknown committed
168
  thd->proc_info="init";
unknown's avatar
unknown committed
169
  table= table_list->table;
unknown's avatar
unknown committed
170 171
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);

172
  /* Calculate "table->used_keys" based on the WHERE */
173
  table->used_keys= table->s->keys_in_use;
174
  table->quick_keys.clear_all();
unknown's avatar
unknown committed
175

unknown's avatar
unknown committed
176
#ifndef NO_EMBEDDED_ACCESS_CHECKS
177 178 179
  /* Force privilege re-checking for views after they have been opened. */
  want_privilege= (table_list->view ? UPDATE_ACL :
                   table_list->grant.want_privilege);
unknown's avatar
unknown committed
180
#endif
181
  if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
unknown's avatar
merge  
unknown committed
182
    DBUG_RETURN(1);
183

unknown's avatar
unknown committed
184
  old_used_keys= table->used_keys;		// Keys used in WHERE
unknown's avatar
unknown committed
185
  /*
186 187
    Change the query_id for the timestamp column so that we can
    check if this is modified directly
unknown's avatar
unknown committed
188
  */
189 190 191 192 193
  if (table->timestamp_field)
  {
    timestamp_query_id=table->timestamp_field->query_id;
    table->timestamp_field->query_id=thd->query_id-1;
  }
unknown's avatar
unknown committed
194

195
  /* Check the fields we are going to modify */
unknown's avatar
unknown committed
196
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
VIEW  
unknown committed
197
  table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
198
  table_list->register_want_access(want_privilege);
unknown's avatar
unknown committed
199
#endif
200 201
  if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0))
    DBUG_RETURN(1);                     /* purecov: inspected */
unknown's avatar
unknown committed
202
  if (table_list->view && check_fields(thd, fields))
unknown's avatar
VIEW  
unknown committed
203
  {
unknown's avatar
merge  
unknown committed
204
    DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
205 206 207
  }
  if (!table_list->updatable || check_key_in_view(thd, table_list))
  {
208
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
unknown's avatar
merge  
unknown committed
209
    DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
210
  }
211 212 213 214
  if (table->timestamp_field)
  {
    // Don't set timestamp column if this is modified
    if (table->timestamp_field->query_id == thd->query_id)
215
      table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
216 217 218
    else
      table->timestamp_field->query_id=timestamp_query_id;
  }
219

unknown's avatar
unknown committed
220
#ifndef NO_EMBEDDED_ACCESS_CHECKS
221
  /* Check values */
unknown's avatar
VIEW  
unknown committed
222
  table_list->grant.want_privilege= table->grant.want_privilege=
unknown's avatar
unknown committed
223
    (SELECT_ACL & ~table->grant.privilege);
unknown's avatar
unknown committed
224
#endif
225
  if (setup_fields(thd, 0, values, 1, 0, 0))
unknown's avatar
unknown committed
226
  {
227
    free_underlaid_joins(thd, select_lex);
unknown's avatar
merge  
unknown committed
228
    DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
229
  }
unknown's avatar
unknown committed
230

231 232 233 234
  if (select_lex->inner_refs_list.elements &&
    fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
    DBUG_RETURN(-1);

235 236 237 238 239 240 241
  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
  }
242
  // Don't count on usage of 'only index' when calculating which key to use
243
  table->used_keys.clear_all();
unknown's avatar
unknown committed
244
  select= make_select(table, 0, 0, conds, 0, &error);
245 246
  if (error || !limit ||
      (select && select->check_quick(thd, safe_update, limit)))
unknown's avatar
unknown committed
247 248
  {
    delete select;
249
    free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
250 251
    if (error)
    {
unknown's avatar
merge  
unknown committed
252
      DBUG_RETURN(1);				// Error in where
unknown's avatar
unknown committed
253
    }
254
    send_ok(thd);				// No matching records
unknown's avatar
unknown committed
255 256
    DBUG_RETURN(0);
  }
257 258
  if (!select && limit != HA_POS_ERROR)
  {
259
    if ((used_index= get_index_for_order(table, order, limit)) != MAX_KEY)
260 261
      need_sort= FALSE;
  }
unknown's avatar
unknown committed
262
  /* If running in safe sql mode, don't allow updates without keys */
263
  if (table->quick_keys.is_clear_all())
unknown's avatar
unknown committed
264
  {
265
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
unknown's avatar
unknown committed
266
    if (safe_update && !using_limit)
267
    {
unknown's avatar
unknown committed
268 269 270
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
		 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
      goto err;
271
    }
unknown's avatar
unknown committed
272
  }
273
  init_ftfuncs(thd, select_lex, 1);
unknown's avatar
unknown committed
274
  /* Check if we are modifying a key that we are used to search with */
275
  
unknown's avatar
unknown committed
276
  if (select && select->quick)
unknown's avatar
unknown committed
277
  {
278
    used_index= select->quick->index;
279
    used_key_is_modified= (!select->quick->unique_key_range() &&
280
                          select->quick->is_keys_used(&fields));
unknown's avatar
unknown committed
281
  }
282
  else
283
  {
284 285 286 287
    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)
288
      used_key_is_modified= is_key_used(table, used_index, fields);
289
  }
290

unknown's avatar
unknown committed
291
  if (used_key_is_modified || order)
unknown's avatar
unknown committed
292 293
  {
    /*
unknown's avatar
unknown committed
294 295
      We can't update table directly;  We must first search after all
      matching rows before updating the table!
unknown's avatar
unknown committed
296
    */
unknown's avatar
unknown committed
297
    table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
298
    if (used_index < MAX_KEY && old_used_keys.is_set(used_index))
unknown's avatar
unknown committed
299 300
    {
      table->key_read=1;
301
      table->file->extra(HA_EXTRA_KEYREAD);
unknown's avatar
unknown committed
302
    }
303

304
    /* note: can actually avoid sorting below.. */
305
    if (order && (need_sort || used_key_is_modified))
306
    {
unknown's avatar
unknown committed
307 308 309 310
      /*
	Doing an ORDER BY;  Let filesort find and sort the rows we are going
	to update
      */
311
      uint         length= 0;
312
      SORT_FIELD  *sortorder;
313
      ha_rows examined_rows;
314

unknown's avatar
unknown committed
315
      table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
unknown's avatar
unknown committed
316
						    MYF(MY_FAE | MY_ZEROFILL));
317
      if (!(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
unknown's avatar
unknown committed
318
          (table->sort.found_records = filesort(thd, table, sortorder, length,
unknown's avatar
unknown committed
319
						select, limit,
unknown's avatar
unknown committed
320
						&examined_rows))
321 322
          == HA_POS_ERROR)
      {
unknown's avatar
unknown committed
323
	free_io_cache(table);
324
	goto err;
325
      }
unknown's avatar
unknown committed
326 327 328 329 330 331
      /*
	Filesort has already found and selected the rows we want to update,
	so we don't need the where clause
      */
      delete select;
      select= 0;
332
    }
unknown's avatar
unknown committed
333
    else
unknown's avatar
unknown committed
334
    {
unknown's avatar
unknown committed
335 336 337 338 339 340 341 342 343
      /*
	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)))
344
	goto err;
unknown's avatar
unknown committed
345

unknown's avatar
unknown committed
346 347 348
      /* If quick select is used, initialize it before retrieving rows. */
      if (select && select->quick && select->quick->reset())
        goto err;
349

350 351 352 353 354 355 356 357 358 359
      /*
        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
      */
360
      if (used_index == MAX_KEY || (select && select->quick))
361 362 363
        init_read_record(&info,thd,table,select,0,1);
      else
        init_read_record_idx(&info, thd, table, 1, used_index);
unknown's avatar
VIEW  
unknown committed
364

unknown's avatar
unknown committed
365
      thd->proc_info="Searching rows for update";
366
      ha_rows tmp_limit= limit;
unknown's avatar
unknown committed
367

unknown's avatar
unknown committed
368
      while (!(error=info.read_record(&info)) && !thd->killed)
unknown's avatar
unknown committed
369
      {
370
	if (!(select && select->skip_record()))
unknown's avatar
unknown committed
371
	{
unknown's avatar
unknown committed
372 373 374 375 376 377 378 379
	  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)
380 381
	  {
	    error= -1;
unknown's avatar
unknown committed
382
	    break;
383
	  }
unknown's avatar
unknown committed
384
	}
unknown's avatar
unknown committed
385 386
	else
	  table->file->unlock_row();
unknown's avatar
unknown committed
387
      }
388 389
      if (thd->killed && !error)
	error= 1;				// Aborted
390
      limit= tmp_limit;
unknown's avatar
unknown committed
391
      end_read_record(&info);
392
     
unknown's avatar
unknown committed
393 394 395 396 397 398 399 400 401
      /* Change select to use tempfile */
      if (select)
      {
	delete select->quick;
	if (select->free_cond)
	  delete select->cond;
	select->quick=0;
	select->cond=0;
      }
unknown's avatar
unknown committed
402 403
      else
      {
unknown's avatar
unknown committed
404 405
	select= new SQL_SELECT;
	select->head=table;
unknown's avatar
unknown committed
406
      }
unknown's avatar
unknown committed
407 408 409 410
      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)
411
	goto err;
unknown's avatar
unknown committed
412 413 414 415 416 417 418 419
    }
    if (table->key_read)
    {
      table->key_read=0;
      table->file->extra(HA_EXTRA_NO_KEYREAD);
    }
  }

420
  if (ignore)
unknown's avatar
unknown committed
421
    table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
422 423 424
  
  if (select && select->quick && select->quick->reset())
        goto err;
unknown's avatar
unknown committed
425 426
  init_read_record(&info,thd,table,select,0,1);

427
  updated= found= 0;
428
  thd->count_cuted_fields= CHECK_FIELD_WARN;		/* calc cuted fields */
unknown's avatar
unknown committed
429
  thd->cuted_fields=0L;
430
  thd->proc_info="Updating";
431
  query_id=thd->query_id;
unknown's avatar
unknown committed
432

unknown's avatar
unknown committed
433
  transactional_table= table->file->has_transactions();
unknown's avatar
unknown committed
434
  thd->abort_on_warning= test(!ignore &&
unknown's avatar
unknown committed
435 436 437
                              (thd->variables.sql_mode &
                               (MODE_STRICT_TRANS_TABLES |
                                MODE_STRICT_ALL_TABLES)));
unknown's avatar
unknown committed
438

439
  if (table->triggers)
440
  {
441
    table->triggers->mark_fields_used(thd, TRG_EVENT_UPDATE);
442 443 444 445 446 447 448 449 450 451 452
    if (table->triggers->has_triggers(TRG_EVENT_UPDATE,
                                      TRG_ACTION_AFTER))
    {
      /*
	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);
    }
  }
453

454 455 456 457 458 459
  /*
    We can use compare_record() to optimize away updates if
    the table handler is returning all columns
  */
  can_compare_record= !(table->file->table_flags() &
                        HA_PARTIAL_COLUMN_READ);
unknown's avatar
unknown committed
460 461
  while (!(error=info.read_record(&info)) && !thd->killed)
  {
462
    if (!(select && select->skip_record()))
unknown's avatar
unknown committed
463
    {
unknown's avatar
unknown committed
464
      store_record(table,record[1]);
unknown's avatar
unknown committed
465 466 467
      if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
                                               table->triggers,
                                               TRG_EVENT_UPDATE))
468
        break; /* purecov: inspected */
unknown's avatar
unknown committed
469

unknown's avatar
unknown committed
470
      found++;
471

472
      if (!can_compare_record || compare_record(table, query_id))
unknown's avatar
unknown committed
473
      {
unknown's avatar
unknown committed
474
        if ((res= table_list->view_check_option(thd, ignore)) !=
unknown's avatar
unknown committed
475 476 477 478 479 480 481 482 483 484 485
            VIEW_CHECK_OK)
        {
          found--;
          if (res == VIEW_CHECK_SKIP)
            continue;
          else if (res == VIEW_CHECK_ERROR)
          {
            error= 1;
            break;
          }
        }
486 487 488 489 490
        if (!(error=table->file->update_row((byte*) table->record[1],
                                            (byte*) table->record[0])))
        {
          updated++;
          
unknown's avatar
unknown committed
491 492 493 494 495 496 497
          if (table->triggers &&
              table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                                TRG_ACTION_AFTER, TRUE))
          {
            error= 1;
            break;
          }
498 499 500
        }
        else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
        {
501 502 503 504 505 506
          /*
            If (ignore && error == HA_ERR_FOUND_DUPP_KEY) we don't have to
            do anything; otherwise...
          */
          if (error != HA_ERR_FOUND_DUPP_KEY)
            thd->fatal_error(); /* Other handler errors are fatal */
507 508 509 510
          table->file->print_error(error,MYF(0));
          error= 1;
          break;
        }
unknown's avatar
unknown committed
511
      }
512
      
unknown's avatar
unknown committed
513 514
      if (!--limit && using_limit)
      {
515 516
        error= -1;				// Simulate end of file
        break;
unknown's avatar
unknown committed
517
      }
unknown's avatar
unknown committed
518
    }
unknown's avatar
unknown committed
519 520
    else
      table->file->unlock_row();
521
    thd->row_count++;
unknown's avatar
unknown committed
522
  }
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
  /*
    Caching the killed status to pass as the arg to query event constuctor;
    The cached value can not change whereas the killed status can
    (externally) since this point and change of the latter won't affect
    binlogging.
    It's assumed that if an error was set in combination with an effective 
    killed status then the error is due to killing.
  */
  killed_status= thd->killed; // get the status of the volatile 
  // simulated killing after the loop must be ineffective for binlogging
  DBUG_EXECUTE_IF("simulate_kill_bug27571",
                  {
                    thd->killed= THD::KILL_QUERY;
                  };);
  error= (killed_status == THD::NOT_KILLED)?  error : 1;
  
539

unknown's avatar
unknown committed
540 541 542
  if (!transactional_table && updated > 0)
    thd->transaction.stmt.modified_non_trans_table= TRUE;

unknown's avatar
unknown committed
543
  end_read_record(&info);
unknown's avatar
unknown committed
544
  free_io_cache(table);				// If ORDER BY
unknown's avatar
unknown committed
545
  delete select;
unknown's avatar
unknown committed
546
  thd->proc_info="end";
unknown's avatar
unknown committed
547
  VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
unknown's avatar
unknown committed
548 549 550 551 552 553

  /*
    Invalidate the table in the query cache if something changed.
    This must be before binlog writing and ha_autocommit_...
  */
  if (updated)
unknown's avatar
unknown committed
554
  {
unknown's avatar
unknown committed
555
    query_cache_invalidate3(thd, table_list, 1);
unknown's avatar
unknown committed
556
  }
unknown's avatar
unknown committed
557

558 559 560 561 562 563 564 565 566
  /*
    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.
  */
567
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
unknown's avatar
unknown committed
568
  {
569 570
    if (mysql_bin_log.is_open())
    {
571
      if (error < 0)
unknown's avatar
unknown committed
572
        thd->clear_error();
573
      Query_log_event qinfo(thd, thd->query, thd->query_length,
574
			    transactional_table, FALSE, killed_status);
575 576
      if (mysql_bin_log.write(&qinfo) && transactional_table)
	error=1;				// Rollback update
577
    }
unknown's avatar
unknown committed
578 579
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
580
  }
unknown's avatar
unknown committed
581
  DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table);
582
  free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
583 584 585 586 587
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd, error >= 0))
      error=1;
  }
unknown's avatar
unknown committed
588

589 590 591 592 593 594
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }

unknown's avatar
unknown committed
595
  if (error < 0)
unknown's avatar
unknown committed
596
  {
unknown's avatar
unknown committed
597
    char buff[STRING_BUFFER_USUAL_SIZE];
598 599
    sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
	    (ulong) thd->cuted_fields);
600 601
    thd->row_count_func=
      (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
602
    send_ok(thd, (ulong) thd->row_count_func,
603
	    thd->insert_id_used ? thd->last_insert_id : 0L,buff);
unknown's avatar
unknown committed
604
    DBUG_PRINT("info",("%ld records updated", (long) updated));
unknown's avatar
unknown committed
605
  }
606
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;		/* calc cuted fields */
607
  thd->abort_on_warning= 0;
unknown's avatar
unknown committed
608
  free_io_cache(table);
unknown's avatar
merge  
unknown committed
609
  DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
610 611 612

err:
  delete select;
613
  free_underlaid_joins(thd, select_lex);
614 615 616 617 618
  if (table->key_read)
  {
    table->key_read=0;
    table->file->extra(HA_EXTRA_NO_KEYREAD);
  }
unknown's avatar
unknown committed
619
  thd->abort_on_warning= 0;
unknown's avatar
merge  
unknown committed
620
  DBUG_RETURN(1);
unknown's avatar
unknown committed
621
}
622

unknown's avatar
unknown committed
623 624 625 626 627 628
/*
  Prepare items in UPDATE statement

  SYNOPSIS
    mysql_prepare_update()
    thd			- thread handler
unknown's avatar
VIEW  
unknown committed
629
    table_list		- global/local table list
unknown's avatar
unknown committed
630 631 632 633 634
    conds		- conditions
    order_num		- number of ORDER BY list entries
    order		- ORDER BY clause list

  RETURN VALUE
unknown's avatar
unknown committed
635 636
    FALSE OK
    TRUE  error
unknown's avatar
unknown committed
637
*/
unknown's avatar
unknown committed
638
bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
unknown's avatar
unknown committed
639 640
			 Item **conds, uint order_num, ORDER *order)
{
641
  Item *fake_conds= 0;
unknown's avatar
unknown committed
642 643 644
  TABLE *table= table_list->table;
  TABLE_LIST tables;
  List<Item> all_fields;
645
  SELECT_LEX *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
646 647 648
  DBUG_ENTER("mysql_prepare_update");

#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
VIEW  
unknown committed
649 650
  table_list->grant.want_privilege= table->grant.want_privilege= 
    (SELECT_ACL & ~table->grant.privilege);
651
  table_list->register_want_access(SELECT_ACL);
unknown's avatar
unknown committed
652 653 654 655 656
#endif

  bzero((char*) &tables,sizeof(tables));	// For ORDER BY
  tables.table= table;
  tables.alias= table_list->alias;
unknown's avatar
unknown committed
657
  thd->lex->allow_sum_func= 0;
unknown's avatar
unknown committed
658

659 660 661 662
  if (setup_tables_and_check_access(thd, &select_lex->context, 
                                    &select_lex->top_join_list,
                                    table_list, conds, 
                                    &select_lex->leaf_tables,
663
                                    FALSE, UPDATE_ACL, SELECT_ACL) ||
664
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
665 666
      select_lex->setup_ref_array(thd, order_num) ||
      setup_order(thd, select_lex->ref_pointer_array,
unknown's avatar
VIEW  
unknown committed
667
		  table_list, all_fields, all_fields, order) ||
668
      setup_ftfuncs(select_lex))
unknown's avatar
unknown committed
669
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
670 671 672

  /* Check that we are not using table that we are updating in a sub select */
  {
673
    TABLE_LIST *duplicate;
674
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
675 676 677 678 679
    {
      update_non_unique_table_error(table_list, "UPDATE", duplicate);
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
      DBUG_RETURN(TRUE);
    }
unknown's avatar
unknown committed
680
  }
681
  select_lex->fix_prepare_information(thd, conds, &fake_conds);
unknown's avatar
unknown committed
682
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
683 684
}

unknown's avatar
unknown committed
685

686
/***************************************************************************
687
  Update multiple tables from join 
688 689
***************************************************************************/

unknown's avatar
unknown committed
690
/*
691
  Get table map for list of Item_field
unknown's avatar
unknown committed
692 693
*/

694 695 696 697 698 699 700 701
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();
unknown's avatar
unknown committed
702
  DBUG_PRINT("info", ("table_map: 0x%08lx", (long) map));
703 704 705 706
  return map;
}


unknown's avatar
VIEW  
unknown committed
707 708
/*
  make update specific preparation and checks after opening tables
unknown's avatar
unknown committed
709

unknown's avatar
VIEW  
unknown committed
710 711 712
  SYNOPSIS
    mysql_multi_update_prepare()
    thd         thread handler
unknown's avatar
unknown committed
713

unknown's avatar
VIEW  
unknown committed
714
  RETURN
unknown's avatar
unknown committed
715 716
    FALSE OK
    TRUE  Error
unknown's avatar
VIEW  
unknown committed
717
*/
718

unknown's avatar
unknown committed
719
bool mysql_multi_update_prepare(THD *thd)
unknown's avatar
VIEW  
unknown committed
720 721 722
{
  LEX *lex= thd->lex;
  TABLE_LIST *table_list= lex->query_tables;
unknown's avatar
unknown committed
723
  TABLE_LIST *tl, *leaves;
unknown's avatar
VIEW  
unknown committed
724
  List<Item> *fields= &lex->select_lex.item_list;
unknown's avatar
unknown committed
725
  table_map tables_for_update;
unknown's avatar
unknown committed
726
  bool update_view= 0;
unknown's avatar
unknown committed
727 728 729 730 731 732
  /*
    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;
unknown's avatar
unknown committed
733
  const bool using_lock_tables= thd->locked_tables != 0;
unknown's avatar
unknown committed
734
  bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
735
  bool need_reopen= FALSE;
unknown's avatar
unknown committed
736 737
  DBUG_ENTER("mysql_multi_update_prepare");

unknown's avatar
unknown committed
738 739
  /* following need for prepared statements, to run next time multi-update */
  thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
unknown's avatar
unknown committed
740

741 742
reopen_tables:

unknown's avatar
unknown committed
743
  /* open tables and create derived ones, but do not lock and fill them */
744
  if (((original_multiupdate || need_reopen) &&
745
       open_tables(thd, &table_list, &table_count, 0)) ||
unknown's avatar
unknown committed
746
      mysql_handle_derived(lex, &mysql_derived_prepare))
747
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
748 749 750 751 752
  /*
    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()).
  */
unknown's avatar
merge  
unknown committed
753

754 755 756 757
  if (setup_tables_and_check_access(thd, &lex->select_lex.context,
                                    &lex->select_lex.top_join_list,
                                    table_list, &lex->select_lex.where,
                                    &lex->select_lex.leaf_tables, FALSE,
758
                                    UPDATE_ACL, SELECT_ACL))
unknown's avatar
merge  
unknown committed
759
    DBUG_RETURN(TRUE);
760

761
  if (setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0))
unknown's avatar
unknown committed
762
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
763 764 765 766 767 768 769 770 771 772 773

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

  if (update_view && check_fields(thd, *fields))
774
  {
unknown's avatar
unknown committed
775
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
776 777
  }

unknown's avatar
unknown committed
778
  tables_for_update= get_table_map(fields);
unknown's avatar
unknown committed
779 780

  /*
unknown's avatar
unknown committed
781
    Setup timestamp handling and locking mode
unknown's avatar
unknown committed
782
  */
783
  leaves= lex->select_lex.leaf_tables;
784
  for (tl= leaves; tl; tl= tl->next_leaf)
785
  {
unknown's avatar
unknown committed
786
    TABLE *table= tl->table;
unknown's avatar
unknown committed
787
    /* Only set timestamp column if this is not modified */
788 789
    if (table->timestamp_field &&
        table->timestamp_field->query_id == thd->query_id)
unknown's avatar
unknown committed
790
      table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
unknown's avatar
VIEW  
unknown committed
791

unknown's avatar
unknown committed
792 793
    /* if table will be updated then check that it is unique */
    if (table->map & tables_for_update)
794
    {
unknown's avatar
unknown committed
795
      if (!tl->updatable || check_key_in_view(thd, tl))
unknown's avatar
unknown committed
796
      {
797
        my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
unknown's avatar
merge  
unknown committed
798
        DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
799
      }
unknown's avatar
unknown committed
800

801 802 803
      if (table->triggers)
        table->triggers->mark_fields_used(thd, TRG_EVENT_UPDATE);

unknown's avatar
unknown committed
804
      DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
805 806 807 808
      /*
        If table will be updated we should not downgrade lock for it and
        leave it as is.
      */
unknown's avatar
unknown committed
809
    }
unknown's avatar
unknown committed
810 811 812
    else
    {
      DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
unknown's avatar
unknown committed
813 814 815 816 817 818
      /*
        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;
unknown's avatar
unknown committed
819
      tl->updating= 0;
820
      /* Update TABLE::lock_type accordingly. */
821
      if (!tl->placeholder() && !using_lock_tables)
822
        tl->table->reginfo.lock_type= tl->lock_type;
823
    }
unknown's avatar
unknown committed
824
  }
unknown's avatar
unknown committed
825
  for (tl= table_list; tl; tl= tl->next_local)
unknown's avatar
unknown committed
826
  {
unknown's avatar
unknown committed
827
    /* Check access privileges for table */
unknown's avatar
unknown committed
828
    if (!tl->derived)
829
    {
unknown's avatar
unknown committed
830 831
      uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL;
      if (check_access(thd, want_privilege,
832 833
                       tl->db, &tl->grant.privilege, 0, 0, 
                       test(tl->schema_table)) ||
unknown's avatar
unknown committed
834
          (grant_option && check_grant(thd, want_privilege, tl, 0, 1, 0)))
unknown's avatar
unknown committed
835
        DBUG_RETURN(TRUE);
836
    }
837
  }
unknown's avatar
unknown committed
838

unknown's avatar
unknown committed
839 840 841
  /* check single table update for view compound from several tables */
  for (tl= table_list; tl; tl= tl->next_local)
  {
unknown's avatar
unknown committed
842
    if (tl->effective_algorithm == VIEW_ALGORITHM_MERGE)
unknown's avatar
unknown committed
843 844
    {
      TABLE_LIST *for_update= 0;
unknown's avatar
unknown committed
845
      if (tl->check_single_table(&for_update, tables_for_update, tl))
unknown's avatar
unknown committed
846 847 848 849 850 851 852 853
      {
	my_error(ER_VIEW_MULTIUPDATE, MYF(0),
		 tl->view_db.str, tl->view_name.str);
	DBUG_RETURN(-1);
      }
    }
  }

unknown's avatar
unknown committed
854
  /* now lock and fill tables */
855
  if (lock_tables(thd, table_list, table_count, &need_reopen))
unknown's avatar
unknown committed
856
  {
857 858 859
    if (!need_reopen)
      DBUG_RETURN(TRUE);

unknown's avatar
unknown committed
860
    /*
861 862 863 864
      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.
unknown's avatar
unknown committed
865 866 867
    */
    List_iterator_fast<Item> it(*fields);
    Item *item;
unknown's avatar
unknown committed
868
    while ((item= it++))
unknown's avatar
unknown committed
869 870
      item->cleanup();

unknown's avatar
unknown committed
871
    /* We have to cleanup translation tables of views. */
unknown's avatar
unknown committed
872 873 874
    for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
      tbl->cleanup_items();

875
    close_tables_for_reopen(thd, &table_list);
876
    goto reopen_tables;
unknown's avatar
unknown committed
877
  }
unknown's avatar
unknown committed
878

879 880 881 882 883
  /*
    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;
unknown's avatar
unknown committed
884 885 886 887 888
  /* 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;
889
    if (!(tlist= tl->top_table())->derived)
unknown's avatar
unknown committed
890 891 892 893 894 895 896
    {
      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));
897
    if (tl->lock_type != TL_READ &&
898
        tl->lock_type != TL_READ_NO_INSERT)
899
    {
900
      TABLE_LIST *duplicate;
901
      if ((duplicate= unique_table(thd, tl, table_list, 0)))
902 903 904 905
      {
        update_non_unique_table_error(table_list, "UPDATE", duplicate);
        DBUG_RETURN(TRUE);
      }
906
    }
unknown's avatar
unknown committed
907
  }
unknown's avatar
unknown committed
908 909 910 911 912 913
  /*
    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;
 
unknown's avatar
unknown committed
914 915
  if (thd->fill_derived_tables() &&
      mysql_handle_derived(lex, &mysql_derived_filling))
916
    DBUG_RETURN(TRUE);
917

unknown's avatar
merge  
unknown committed
918
  DBUG_RETURN (FALSE);
unknown's avatar
VIEW  
unknown committed
919 920 921
}


unknown's avatar
unknown committed
922 923 924
/*
  Setup multi-update handling and call SELECT to do the join
*/
925

unknown's avatar
unknown committed
926 927 928 929 930
bool mysql_multi_update(THD *thd,
                        TABLE_LIST *table_list,
                        List<Item> *fields,
                        List<Item> *values,
                        COND *conds,
931
                        ulonglong options,
932
                        enum enum_duplicates handle_duplicates, bool ignore,
unknown's avatar
unknown committed
933
                        SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
unknown's avatar
VIEW  
unknown committed
934 935
{
  multi_update *result;
936
  bool res;
unknown's avatar
VIEW  
unknown committed
937 938
  DBUG_ENTER("mysql_multi_update");

939
  if (!(result= new multi_update(table_list,
940 941
				 thd->lex->select_lex.leaf_tables,
				 fields, values,
942
				 handle_duplicates, ignore)))
unknown's avatar
unknown committed
943
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
944

unknown's avatar
unknown committed
945 946 947 948
  thd->abort_on_warning= test(thd->variables.sql_mode &
                              (MODE_STRICT_TRANS_TABLES |
                               MODE_STRICT_ALL_TABLES));

unknown's avatar
unknown committed
949
  List<Item> total_list;
950
  res= mysql_select(thd, &select_lex->ref_pointer_array,
951 952 953 954 955 956 957
                      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);
958 959 960 961 962 963 964 965 966
  DBUG_PRINT("info",("res: %d  report_error: %d", res,
                     thd->net.report_error));
  res|= thd->net.report_error;
  if (unlikely(res))
  {
    /* If we had a another error reported earlier then this will be ignored */
    result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
    result->abort();
  }
unknown's avatar
unknown committed
967
  delete result;
unknown's avatar
unknown committed
968
  thd->abort_on_warning= 0;
969
  DBUG_RETURN(FALSE);
970 971
}

unknown's avatar
unknown committed
972

973
multi_update::multi_update(TABLE_LIST *table_list,
974
			   TABLE_LIST *leaves_list,
unknown's avatar
unknown committed
975
			   List<Item> *field_list, List<Item> *value_list,
unknown's avatar
unknown committed
976 977
			   enum enum_duplicates handle_duplicates_arg,
                           bool ignore_arg)
978
  :all_tables(table_list), leaves(leaves_list), update_tables(0),
979
   tmp_tables(0), updated(0), found(0), fields(field_list),
980
   values(value_list), table_count(0), copy_field(0),
981
   handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
982
   transactional_tables(0), ignore(ignore_arg), error_handled(0)
unknown's avatar
unknown committed
983 984 985 986 987 988 989
{}


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

990 991
int multi_update::prepare(List<Item> &not_used_values,
			  SELECT_LEX_UNIT *lex_unit)
992
{
unknown's avatar
unknown committed
993 994
  TABLE_LIST *table_ref;
  SQL_LIST update;
995
  table_map tables_to_update;
unknown's avatar
unknown committed
996 997 998 999
  Item_field *item;
  List_iterator_fast<Item> field_it(*fields);
  List_iterator_fast<Item> value_it(*values);
  uint i, max_fields;
unknown's avatar
unknown committed
1000
  uint leaf_table_count= 0;
1001
  DBUG_ENTER("multi_update::prepare");
unknown's avatar
unknown committed
1002

1003
  thd->count_cuted_fields= CHECK_FIELD_WARN;
1004
  thd->cuted_fields=0L;
unknown's avatar
unknown committed
1005 1006
  thd->proc_info="updating main table";

1007
  tables_to_update= get_table_map(fields);
1008

unknown's avatar
unknown committed
1009
  if (!tables_to_update)
1010
  {
unknown's avatar
unknown committed
1011
    my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
unknown's avatar
unknown committed
1012
    DBUG_RETURN(1);
1013
  }
unknown's avatar
unknown committed
1014

1015
  /*
unknown's avatar
unknown committed
1016 1017
    We have to check values after setup_tables to get used_keys right in
    reference tables
1018
  */
1019

1020
  if (setup_fields(thd, 0, *values, 1, 0, 0))
1021 1022
    DBUG_RETURN(1);

1023
  /*
unknown's avatar
unknown committed
1024 1025 1026
    Save tables beeing updated in update_tables
    update_table->shared is position for table
    Don't use key read on tables that are updated
1027
  */
unknown's avatar
unknown committed
1028 1029

  update.empty();
1030
  for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
1031
  {
1032
    /* TODO: add support of view of join support */
unknown's avatar
unknown committed
1033
    TABLE *table=table_ref->table;
unknown's avatar
unknown committed
1034
    leaf_table_count++;
unknown's avatar
unknown committed
1035
    if (tables_to_update & table->map)
1036
    {
unknown's avatar
unknown committed
1037 1038 1039
      TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
						sizeof(*tl));
      if (!tl)
1040
	DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
1041
      update.link_in_list((byte*) tl, (byte**) &tl->next_local);
unknown's avatar
unknown committed
1042 1043
      tl->shared= table_count++;
      table->no_keyread=1;
1044
      table->used_keys.clear_all();
unknown's avatar
unknown committed
1045
      table->pos_in_table_list= tl;
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
      if (table->triggers)
      {
	table->triggers->mark_fields_used(thd, TRG_EVENT_UPDATE);
	if (table->triggers->has_triggers(TRG_EVENT_UPDATE,
					  TRG_ACTION_AFTER))
	{
	  /*
	    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);
	}
      }
1060 1061
    }
  }
unknown's avatar
unknown committed
1062 1063


unknown's avatar
unknown committed
1064 1065 1066
  table_count=  update.elements;
  update_tables= (TABLE_LIST*) update.first;

1067
  tmp_tables = (TABLE**) thd->calloc(sizeof(TABLE *) * table_count);
unknown's avatar
unknown committed
1068 1069 1070 1071 1072 1073
  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);
1074
  if (thd->is_fatal_error)
unknown's avatar
unknown committed
1075 1076 1077 1078 1079 1080
    DBUG_RETURN(1);
  for (i=0 ; i < table_count ; i++)
  {
    fields_for_table[i]= new List_item;
    values_for_table[i]= new List_item;
  }
1081
  if (thd->is_fatal_error)
unknown's avatar
unknown committed
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
    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);
  }
1093
  if (thd->is_fatal_error)
unknown's avatar
unknown committed
1094 1095 1096 1097 1098
    DBUG_RETURN(1);

  /* Allocate copy fields */
  max_fields=0;
  for (i=0 ; i < table_count ; i++)
unknown's avatar
unknown committed
1099
    set_if_bigger(max_fields, fields_for_table[i]->elements + leaf_table_count);
unknown's avatar
unknown committed
1100
  copy_field= new Copy_field[max_fields];
1101 1102
  DBUG_RETURN(thd->is_fatal_error != 0);
}
1103 1104


1105 1106
/*
  Check if table is safe to update on fly
1107

1108 1109 1110 1111 1112 1113
  SYNOPSIS
    safe_update_on_fly()
    thd                 Thread handler
    join_tab            How table is used in join
    all_tables          List of tables
    fields              Fields that are updated
1114

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
  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.

1128 1129 1130 1131
    When checking for above cases we also should take into account that
    BEFORE UPDATE trigger potentially may change value of any field in row
    being updated.

1132 1133 1134 1135 1136 1137 1138 1139 1140
  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,
unknown's avatar
unknown committed
1141 1142
                               TABLE_LIST *table_ref, TABLE_LIST *all_tables,
                               List<Item> *fields)
1143 1144
{
  TABLE *table= join_tab->table;
1145
  if (unique_table(thd, table_ref, all_tables, 0))
1146 1147 1148 1149 1150
    return 0;
  switch (join_tab->type) {
  case JT_SYSTEM:
  case JT_CONST:
  case JT_EQ_REF:
1151
    return TRUE;				// At most one matching row
1152
  case JT_REF:
1153 1154
  case JT_REF_OR_NULL:
    return !is_key_used(table, join_tab->ref.key, *fields);
1155 1156 1157
  case JT_ALL:
    /* If range search on index */
    if (join_tab->quick)
1158
      return !join_tab->quick->is_keys_used(fields);
1159 1160
    /* If scanning in clustered key */
    if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
1161 1162 1163
	table->s->primary_key < MAX_KEY)
      return !is_key_used(table, table->s->primary_key, *fields);
    return TRUE;
1164 1165
  default:
    break;					// Avoid compler warning
1166
  }
1167
  return FALSE;
1168 1169 1170
}


unknown's avatar
unknown committed
1171
/*
1172
  Initialize table for multi table
unknown's avatar
unknown committed
1173

1174 1175 1176 1177
  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).
unknown's avatar
unknown committed
1178 1179 1180
*/

bool
1181 1182
multi_update::initialize_tables(JOIN *join)
{
unknown's avatar
unknown committed
1183 1184 1185 1186 1187 1188
  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;
1189 1190
  table_to_update= 0;

unknown's avatar
unknown committed
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
  /* Any update has at least one pair (field, value) */
  DBUG_ASSERT(fields->elements);
  /*
   Only one table may be modified by UPDATE of an updatable view.
   For an updatable view first_table_for_update indicates this
   table.
   For a regular multi-update it refers to some updated table.
  */ 
  TABLE *first_table_for_update= ((Item_field *) fields->head())->field->table;

1201
  /* Create a temporary table for keys to all tables, except main table */
unknown's avatar
VIEW  
unknown committed
1202
  for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
1203
  {
unknown's avatar
unknown committed
1204
    TABLE *table=table_ref->table;
1205
    uint cnt= table_ref->shared;
unknown's avatar
unknown committed
1206
    List<Item> temp_fields;
1207
    ORDER     group;
unknown's avatar
unknown committed
1208

1209 1210
    if (ignore)
      table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1211 1212
    if (table == main_table)			// First table in join
    {
unknown's avatar
unknown committed
1213
      if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables,
unknown's avatar
unknown committed
1214
                             fields_for_table[cnt]))
1215 1216 1217 1218
      {
	table_to_update= main_table;		// Update table on the fly
	continue;
      }
1219
    }
1220

unknown's avatar
unknown committed
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
    if (table == first_table_for_update && table_ref->check_option)
    {
      table_map unupdated_tables= table_ref->check_option->used_tables() &
                                  ~first_table_for_update->map;
      for (TABLE_LIST *tbl_ref =leaves;
           unupdated_tables && tbl_ref;
           tbl_ref= tbl_ref->next_leaf)
      {
        if (unupdated_tables & tbl_ref->table->map)
          unupdated_tables&= ~tbl_ref->table->map;
        else
          continue;
        if (unupdated_check_opt_tables.push_back(tbl_ref->table))
          DBUG_RETURN(1);
      }
    }

1238 1239 1240 1241 1242
    TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;

    /*
      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
unknown's avatar
unknown committed
1243 1244 1245
      original row so that we can find and update it. For the updatable
      VIEW a few following fields are rowids of tables used in the CHECK
      OPTION condition.
1246 1247
    */

unknown's avatar
unknown committed
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
    List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
    TABLE *tbl= table;
    do
    {
      Field_string *field= new Field_string(tbl->file->ref_length, 0,
                                            tbl->alias,
                                            tbl, &my_charset_bin);
      if (!field)
        DBUG_RETURN(1);
      /*
        The field will be converted to varstring when creating tmp table if
        table to be updated was created by mysql 4.1. Deny this.
      */
      field->can_alter_field_type= 0;
      Item_field *ifield= new Item_field((Field *) field);
      if (!ifield)
         DBUG_RETURN(1);
      ifield->maybe_null= 0;
      if (temp_fields.push_back(ifield))
        DBUG_RETURN(1);
    } while ((tbl= tbl_it++));

    temp_fields.concat(fields_for_table[cnt]);
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283

    /* 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,
unknown's avatar
unknown committed
1284 1285
					   (ORDER*) &group, 0, 0,
					   TMP_TABLE_ALL_COLUMNS,
1286 1287
					   HA_POS_ERROR,
					   (char *) "")))
1288 1289
      DBUG_RETURN(1);
    tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
1290
  }
unknown's avatar
unknown committed
1291
  DBUG_RETURN(0);
1292 1293 1294 1295 1296
}


multi_update::~multi_update()
{
unknown's avatar
unknown committed
1297
  TABLE_LIST *table;
unknown's avatar
VIEW  
unknown committed
1298
  for (table= update_tables ; table; table= table->next_local)
1299
  {
1300
    table->table->no_keyread= table->table->no_cache= 0;
1301 1302 1303
    if (ignore)
      table->table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
  }
unknown's avatar
unknown committed
1304

1305 1306
  if (tmp_tables)
  {
1307 1308 1309 1310 1311 1312 1313 1314
    for (uint cnt = 0; cnt < table_count; cnt++)
    {
      if (tmp_tables[cnt])
      {
	free_tmp_table(thd, tmp_tables[cnt]);
	tmp_table_param[cnt].cleanup();
      }
    }
1315
  }
unknown's avatar
unknown committed
1316 1317
  if (copy_field)
    delete [] copy_field;
1318
  thd->count_cuted_fields= CHECK_FIELD_IGNORE;		// Restore this setting
1319 1320
  DBUG_ASSERT(trans_safe || !updated || 
              thd->transaction.all.modified_non_trans_table);
1321 1322 1323
}


unknown's avatar
unknown committed
1324
bool multi_update::send_data(List<Item> &not_used_values)
1325
{
unknown's avatar
unknown committed
1326 1327 1328
  TABLE_LIST *cur_table;
  DBUG_ENTER("multi_update::send_data");

unknown's avatar
VIEW  
unknown committed
1329
  for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
1330
  {
unknown's avatar
unknown committed
1331
    TABLE *table= cur_table->table;
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
    /*
      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.
    */
unknown's avatar
unknown committed
1344 1345 1346 1347 1348
    if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
      continue;

    uint offset= cur_table->shared;
    table->file->position(table->record[0]);
1349 1350 1351 1352
    /*
      We can use compare_record() to optimize away updates if
      the table handler is returning all columns
    */
1353
    if (table == table_to_update)
1354
    {
1355 1356 1357
      bool can_compare_record;
      can_compare_record= !(table->file->table_flags() &
                            HA_PARTIAL_COLUMN_READ);
1358
      table->status|= STATUS_UPDATED;
unknown's avatar
unknown committed
1359
      store_record(table,record[1]);
unknown's avatar
unknown committed
1360 1361 1362 1363
      if (fill_record_n_invoke_before_triggers(thd, *fields_for_table[offset],
                                               *values_for_table[offset], 0,
                                               table->triggers,
                                               TRG_EVENT_UPDATE))
unknown's avatar
unknown committed
1364
	DBUG_RETURN(1);
unknown's avatar
unknown committed
1365

1366
      found++;
1367
      if (!can_compare_record || compare_record(table, thd->query_id))
1368
      {
unknown's avatar
unknown committed
1369
	int error;
unknown's avatar
unknown committed
1370
        if ((error= cur_table->view_check_option(thd, ignore)) !=
unknown's avatar
unknown committed
1371 1372 1373 1374 1375 1376 1377 1378
            VIEW_CHECK_OK)
        {
          found--;
          if (error == VIEW_CHECK_SKIP)
            continue;
          else if (error == VIEW_CHECK_ERROR)
            DBUG_RETURN(1);
        }
unknown's avatar
unknown committed
1379
	if (!updated++)
1380
	{
unknown's avatar
unknown committed
1381 1382 1383 1384 1385 1386
	  /*
	    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);
1387
	}
unknown's avatar
unknown committed
1388 1389
	if ((error=table->file->update_row(table->record[1],
					   table->record[0])))
1390
	{
unknown's avatar
unknown committed
1391
	  updated--;
1392
          if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
1393
	  {
1394 1395 1396 1397 1398 1399
            /*
              If (ignore && error == HA_ERR_FOUND_DUPP_KEY) we don't have to
              do anything; otherwise...
            */
            if (error != HA_ERR_FOUND_DUPP_KEY)
              thd->fatal_error(); /* Other handler errors are fatal */
1400 1401 1402
	    table->file->print_error(error,MYF(0));
	    DBUG_RETURN(1);
	  }
1403
	}
unknown's avatar
unknown committed
1404 1405
        else
        {
1406 1407 1408 1409 1410 1411 1412
          /* non-transactional or transactional table got modified   */
          /* either multi_update class' flag is raised in its branch */
          if (table->file->has_transactions())
            transactional_tables= 1;
          else
          {
            trans_safe= 0;
unknown's avatar
unknown committed
1413
            thd->transaction.stmt.modified_non_trans_table= TRUE;
1414
          }
unknown's avatar
unknown committed
1415 1416 1417 1418 1419
          if (table->triggers &&
              table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                                TRG_ACTION_AFTER, TRUE))
	    DBUG_RETURN(1);
        }
1420
      }
unknown's avatar
unknown committed
1421 1422 1423 1424 1425
    }
    else
    {
      int error;
      TABLE *tmp_table= tmp_tables[offset];
unknown's avatar
unknown committed
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
      /* Store regular updated fields in the row. */
      fill_record(thd,
                  tmp_table->field + 1 + unupdated_check_opt_tables.elements,
                  *values_for_table[offset], 1);
      /*
       For updatable VIEW store rowid of the updated table and
       rowids of tables used in the CHECK OPTION condition.
      */
      uint field_num= 0;
      List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
      TABLE *tbl= table;
      do
      {
        if (tbl != table)
          tbl->file->position(tbl->record[0]);
        memcpy((char*) tmp_table->field[field_num]->ptr,
               (char*) tbl->file->ref, tbl->file->ref_length);
        field_num++;
      } while ((tbl= tbl_it++));

unknown's avatar
unknown committed
1446
      /* Write row, ignoring duplicated updates to a row */
1447 1448
      error= tmp_table->file->write_row(tmp_table->record[0]);
      if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
1449
      {
1450
        if (error &&
1451
            create_myisam_from_heap(thd, tmp_table,
1452 1453 1454 1455 1456
                                    tmp_table_param + offset, error, 1))
        {
          do_update= 0;
          DBUG_RETURN(1);			// Not a table_is_full error
        }
1457
        found++;
1458
      }
1459 1460
    }
  }
unknown's avatar
unknown committed
1461
  DBUG_RETURN(0);
1462 1463
}

unknown's avatar
unknown committed
1464

1465 1466 1467
void multi_update::send_error(uint errcode,const char *err)
{
  /* First send error what ever it is ... */
unknown's avatar
unknown committed
1468
  my_error(errcode, MYF(0), err);
1469

1470 1471 1472 1473
  /* the error was handled or nothing deleted and no side effects return */
  if (error_handled ||
      !thd->transaction.stmt.modified_non_trans_table && !updated)
    return;
1474

1475
  /* Something already updated so we have to invalidate cache */
1476 1477
  if (updated)
    query_cache_invalidate3(thd, update_tables, 1);
1478
  /*
unknown's avatar
unknown committed
1479 1480
    If all tables that has been updated are trans safe then just do rollback.
    If not attempt to do remaining updates.
1481
  */
unknown's avatar
unknown committed
1482 1483 1484

  if (trans_safe)
  {
1485 1486 1487 1488 1489
    DBUG_ASSERT(transactional_tables);
    (void) ha_autocommit_or_rollback(thd, 1);
  }
  else
  { 
unknown's avatar
unknown committed
1490
    DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table);
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500
    if (do_update && table_count > 1)
    {
      /* Add warning here */
      /* 
         todo/fixme: do_update() is never called with the arg 1.
         should it change the signature to become argless?
      */
      VOID(do_updates(0));
    }
  }
unknown's avatar
unknown committed
1501
  if (thd->transaction.stmt.modified_non_trans_table)
1502 1503 1504 1505 1506 1507 1508
  {
    /*
      The query has to binlog because there's a modified non-transactional table
      either from the query's list or via a stored routine: bug#13270,23333
    */
    if (mysql_bin_log.is_open())
    {
1509 1510 1511 1512 1513
      /*
        THD::killed status might not have been set ON at time of an error
        got caught and if happens later the killed error is written
        into repl event.
      */
1514 1515 1516 1517
      Query_log_event qinfo(thd, thd->query, thd->query_length,
                            transactional_tables, FALSE);
      mysql_bin_log.write(&qinfo);
    }
1518
    thd->transaction.all.modified_non_trans_table= TRUE;
1519
  }
unknown's avatar
unknown committed
1520
  DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table);
1521 1522 1523 1524
  
  if (transactional_tables)
  {
    (void) ha_autocommit_or_rollback(thd, 1);
unknown's avatar
unknown committed
1525
  }
1526 1527 1528
}


unknown's avatar
unknown committed
1529
int multi_update::do_updates(bool from_send_error)
1530
{
unknown's avatar
unknown committed
1531
  TABLE_LIST *cur_table;
unknown's avatar
unknown committed
1532
  int local_error= 0;
unknown's avatar
unknown committed
1533
  ha_rows org_updated;
unknown's avatar
unknown committed
1534
  TABLE *table, *tmp_table;
unknown's avatar
unknown committed
1535
  List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables);
unknown's avatar
unknown committed
1536 1537
  DBUG_ENTER("do_updates");

unknown's avatar
unknown committed
1538
  do_update= 0;					// Don't retry this function
1539
  if (!found)
unknown's avatar
unknown committed
1540
    DBUG_RETURN(0);
unknown's avatar
VIEW  
unknown committed
1541
  for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
1542
  {
1543
    bool can_compare_record;
unknown's avatar
unknown committed
1544
    uint offset= cur_table->shared;
unknown's avatar
unknown committed
1545

unknown's avatar
unknown committed
1546
    table = cur_table->table;
1547
    if (table == table_to_update)
unknown's avatar
unknown committed
1548 1549
      continue;					// Already updated
    org_updated= updated;
1550
    tmp_table= tmp_tables[cur_table->shared];
unknown's avatar
unknown committed
1551
    tmp_table->file->extra(HA_EXTRA_CACHE);	// Change to read cache
unknown's avatar
unknown committed
1552
    (void) table->file->ha_rnd_init(0);
unknown's avatar
unknown committed
1553 1554
    table->file->extra(HA_EXTRA_NO_CACHE);

unknown's avatar
unknown committed
1555 1556 1557 1558 1559 1560 1561 1562
    check_opt_it.rewind();
    while(TABLE *tbl= check_opt_it++)
    {
      if (tbl->file->ha_rnd_init(1))
        goto err;
      tbl->file->extra(HA_EXTRA_CACHE);
    }

unknown's avatar
unknown committed
1563 1564 1565
    /*
      Setup copy functions to copy fields from temporary table
    */
unknown's avatar
unknown committed
1566 1567 1568
    List_iterator_fast<Item> field_it(*fields_for_table[offset]);
    Field **field= tmp_table->field + 
                   1 + unupdated_check_opt_tables.elements; // Skip row pointers
unknown's avatar
unknown committed
1569 1570
    Copy_field *copy_field_ptr= copy_field, *copy_field_end;
    for ( ; *field ; field++)
1571
    {
unknown's avatar
unknown committed
1572 1573
      Item_field *item= (Item_field* ) field_it++;
      (copy_field_ptr++)->set(item->field, *field, 0);
1574
    }
unknown's avatar
unknown committed
1575 1576
    copy_field_end=copy_field_ptr;

unknown's avatar
unknown committed
1577
    if ((local_error = tmp_table->file->ha_rnd_init(1)))
unknown's avatar
unknown committed
1578 1579
      goto err;

1580 1581 1582
    can_compare_record= !(table->file->table_flags() &
                          HA_PARTIAL_COLUMN_READ);

unknown's avatar
unknown committed
1583
    for (;;)
1584
    {
unknown's avatar
unknown committed
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
      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;
      }
unknown's avatar
unknown committed
1595 1596 1597 1598 1599 1600 1601

      /* call rnd_pos() using rowids from temporary table */
      check_opt_it.rewind();
      TABLE *tbl= table;
      uint field_num= 0;
      do
      {
unknown's avatar
unknown committed
1602 1603 1604
        if((local_error=
              tbl->file->rnd_pos(tbl->record[0],
                                (byte *) tmp_table->field[field_num]->ptr)))
unknown's avatar
unknown committed
1605 1606 1607 1608
          goto err;
        field_num++;
      } while((tbl= check_opt_it++));

1609
      table->status|= STATUS_UPDATED;
unknown's avatar
unknown committed
1610
      store_record(table,record[1]);
unknown's avatar
unknown committed
1611 1612 1613 1614 1615 1616 1617

      /* 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);

unknown's avatar
unknown committed
1618 1619 1620 1621 1622
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                            TRG_ACTION_BEFORE, TRUE))
        goto err2;

1623
      if (!can_compare_record || compare_record(table, thd->query_id))
1624
      {
unknown's avatar
unknown committed
1625 1626 1627 1628 1629 1630 1631 1632 1633
        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;
        }
unknown's avatar
unknown committed
1634 1635 1636
	if ((local_error=table->file->update_row(table->record[1],
						 table->record[0])))
	{
1637
	  if (!ignore || local_error != HA_ERR_FOUND_DUPP_KEY)
unknown's avatar
unknown committed
1638 1639 1640
	    goto err;
	}
	updated++;
unknown's avatar
unknown committed
1641 1642 1643 1644 1645

        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
                                              TRG_ACTION_AFTER, TRUE))
          goto err2;
1646
      }
unknown's avatar
unknown committed
1647 1648 1649 1650 1651
    }

    if (updated != org_updated)
    {
      if (table->file->has_transactions())
1652
        transactional_tables= 1;
1653
      else
1654 1655
      {
        trans_safe= 0;				// Can't do safe rollback
unknown's avatar
unknown committed
1656
        thd->transaction.stmt.modified_non_trans_table= TRUE;
1657
      }
1658
    }
unknown's avatar
unknown committed
1659 1660
    (void) table->file->ha_rnd_end();
    (void) tmp_table->file->ha_rnd_end();
unknown's avatar
unknown committed
1661 1662 1663 1664
    check_opt_it.rewind();
    while (TABLE *tbl= check_opt_it++)
        tbl->file->ha_rnd_end();

1665
  }
unknown's avatar
unknown committed
1666 1667 1668 1669
  DBUG_RETURN(0);

err:
  if (!from_send_error)
unknown's avatar
unknown committed
1670 1671
  {
    thd->fatal_error();
unknown's avatar
unknown committed
1672
    table->file->print_error(local_error,MYF(0));
unknown's avatar
unknown committed
1673
  }
unknown's avatar
unknown committed
1674

unknown's avatar
unknown committed
1675
err2:
unknown's avatar
unknown committed
1676 1677
  (void) table->file->ha_rnd_end();
  (void) tmp_table->file->ha_rnd_end();
unknown's avatar
unknown committed
1678 1679 1680
  check_opt_it.rewind();
  while (TABLE *tbl= check_opt_it++)
      tbl->file->ha_rnd_end();
unknown's avatar
unknown committed
1681

unknown's avatar
unknown committed
1682 1683 1684
  if (updated != org_updated)
  {
    if (table->file->has_transactions())
unknown's avatar
unknown committed
1685
      transactional_tables= 1;
unknown's avatar
unknown committed
1686
    else
1687
    {
unknown's avatar
unknown committed
1688
      trans_safe= 0;
unknown's avatar
unknown committed
1689
      thd->transaction.stmt.modified_non_trans_table= TRUE;
1690
    }
unknown's avatar
unknown committed
1691 1692
  }
  DBUG_RETURN(1);
1693 1694 1695
}


unknown's avatar
unknown committed
1696 1697
/* out: 1 if error, 0 if success */

1698 1699
bool multi_update::send_eof()
{
unknown's avatar
unknown committed
1700
  char buff[STRING_BUFFER_USUAL_SIZE];
1701
  THD::killed_state killed_status= THD::NOT_KILLED;
unknown's avatar
unknown committed
1702
  thd->proc_info="updating reference tables";
1703

1704 1705 1706 1707
  /* 
     Does updates for the last n - 1 tables, returns 0 if ok;
     error takes into account killed status gained in do_updates()
  */
unknown's avatar
unknown committed
1708
  int local_error = (table_count) ? do_updates(0) : 0;
1709 1710 1711 1712 1713
  /*
    if local_error is not set ON until after do_updates() then
    later carried out killing should not affect binlogging.
  */
  killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
1714
  thd->proc_info= "end";
1715

unknown's avatar
unknown committed
1716 1717 1718 1719 1720 1721 1722
  /* We must invalidate the query cache before binlog writing and
  ha_autocommit_... */

  if (updated)
  {
    query_cache_invalidate3(thd, update_tables, 1);
  }
unknown's avatar
unknown committed
1723 1724
  /*
    Write the SQL statement to the binlog if we updated
unknown's avatar
unknown committed
1725
    rows and we succeeded or if we updated some non
1726
    transactional tables.
1727 1728 1729
    
    The query has to binlog because there's a modified non-transactional table
    either from the query's list or via a stored routine: bug#13270,23333
unknown's avatar
unknown committed
1730
  */
1731

unknown's avatar
unknown committed
1732 1733 1734
  DBUG_ASSERT(trans_safe || !updated || 
              thd->transaction.stmt.modified_non_trans_table);
  if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table)
1735
  {
unknown's avatar
unknown committed
1736 1737
    if (mysql_bin_log.is_open())
    {
1738
      if (local_error == 0)
unknown's avatar
unknown committed
1739
        thd->clear_error();
unknown's avatar
unknown committed
1740
      Query_log_event qinfo(thd, thd->query, thd->query_length,
1741
			    transactional_tables, FALSE, killed_status);
unknown's avatar
unknown committed
1742
      if (mysql_bin_log.write(&qinfo) && trans_safe)
1743
        local_error= 1;				// Rollback update
unknown's avatar
unknown committed
1744
    }
unknown's avatar
unknown committed
1745 1746
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
1747
  }
1748 1749
  if (local_error != 0)
    error_handled= TRUE; // to force early leave from ::send_error()
1750

unknown's avatar
unknown committed
1751 1752
  if (transactional_tables)
  {
1753
    if (ha_autocommit_or_rollback(thd, local_error != 0))
unknown's avatar
unknown committed
1754 1755
      local_error=1;
  }
1756

unknown's avatar
unknown committed
1757 1758
  if (local_error > 0) // if the above log write did not fail ...
  {
1759
    /* Safety: If we haven't got an error before (can happen in do_updates) */
unknown's avatar
unknown committed
1760 1761
    my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
	       MYF(0));
1762
    return TRUE;
1763
  }
unknown's avatar
unknown committed
1764 1765


1766 1767
  sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
	  (ulong) thd->cuted_fields);
1768 1769
  thd->row_count_func=
    (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
1770
  ::send_ok(thd, (ulong) thd->row_count_func,
1771
	    thd->insert_id_used ? thd->last_insert_id : 0L,buff);
1772
  return FALSE;
1773
}