sql_delete.cc 23.5 KB
Newer Older
1
/* Copyright (C) 2000 MySQL AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   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
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   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.
unknown's avatar
unknown committed
12

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

unknown's avatar
unknown committed
18
/*
19
  Delete of records and truncate of tables.
20

21
  Multi-table deletes were introduced by Monty and Sinisa
unknown's avatar
unknown committed
22 23
*/

24 25


26
#include "mysql_priv.h"
27
#include "ha_innodb.h"
28
#include "sql_select.h"
29 30
#include "sp_head.h"
#include "sql_trigger.h"
unknown's avatar
unknown committed
31

unknown's avatar
unknown committed
32 33
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
                  SQL_LIST *order, ha_rows limit, ulong options)
unknown's avatar
unknown committed
34 35 36
{
  int		error;
  TABLE		*table;
37
  SQL_SELECT	*select=0;
unknown's avatar
unknown committed
38
  READ_RECORD	info;
unknown's avatar
unknown committed
39 40
  bool          using_limit=limit != HA_POS_ERROR;
  bool		transactional_table, safe_update, const_cond;
41
  ha_rows	deleted;
42
  SELECT_LEX   *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
43 44
  DBUG_ENTER("mysql_delete");

unknown's avatar
unknown committed
45 46
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
47 48 49 50
  if (!(table= table_list->table))
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
	     table_list->view_db.str, table_list->view_name.str);
unknown's avatar
unknown committed
51
    DBUG_RETURN(TRUE);
52
  }
53
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
unknown's avatar
unknown committed
54 55
  thd->proc_info="init";
  table->map=1;
unknown's avatar
unknown committed
56

unknown's avatar
unknown committed
57 58
  if (mysql_prepare_delete(thd, table_list, &conds))
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
59

60 61 62 63
  const_cond= (!conds || conds->const_item());
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
  if (safe_update && const_cond)
  {
unknown's avatar
unknown committed
64 65
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
66
    DBUG_RETURN(TRUE);
67 68
  }

69
  select_lex->no_error= thd->lex->ignore;
70

71 72 73 74 75
  /*
    Test if the user wants to delete all rows and deletion doesn't have
    any side-effects (because of triggers), so we can use optimized
    handler::delete_all_rows() method.
  */
unknown's avatar
unknown committed
76
  if (!using_limit && const_cond && (!conds || conds->val_int()) &&
77 78
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
      !(table->triggers && table->triggers->has_delete_triggers()))
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
  {
    deleted= table->file->records;
    if (!(error=table->file->delete_all_rows()))
    {
      error= -1;				// ok
      goto cleanup;
    }
    if (error != HA_ERR_WRONG_COMMAND)
    {
      table->file->print_error(error,MYF(0));
      error=0;
      goto cleanup;
    }
    /* Handler didn't support fast delete; Delete rows one by one */
  }

95 96
  table->used_keys.clear_all();
  table->quick_keys.clear_all();		// Can't use 'only index'
unknown's avatar
unknown committed
97
  select=make_select(table, 0, 0, conds, 0, &error);
unknown's avatar
unknown committed
98
  if (error)
unknown's avatar
unknown committed
99
    DBUG_RETURN(TRUE);
100
  if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
unknown's avatar
unknown committed
101 102
  {
    delete select;
103
    free_underlaid_joins(thd, select_lex);
104
    thd->row_count_func= 0;
105
    send_ok(thd,0L);
unknown's avatar
unknown committed
106
    DBUG_RETURN(0);				// Nothing to delete
unknown's avatar
unknown committed
107 108 109
  }

  /* If running in safe sql mode, don't allow updates without keys */
110
  if (table->quick_keys.is_clear_all())
unknown's avatar
unknown committed
111
  {
112
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
unknown's avatar
unknown committed
113
    if (safe_update && !using_limit)
114 115
    {
      delete select;
116
      free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
117 118
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
119
      DBUG_RETURN(TRUE);
120
    }
unknown's avatar
unknown committed
121
  }
122
  if (options & OPTION_QUICK)
123 124
    (void) table->file->extra(HA_EXTRA_QUICK);

125
  if (order && order->elements)
126 127 128 129 130 131
  {
    uint         length;
    SORT_FIELD  *sortorder;
    TABLE_LIST   tables;
    List<Item>   fields;
    List<Item>   all_fields;
132
    ha_rows examined_rows;
133 134 135

    bzero((char*) &tables,sizeof(tables));
    tables.table = table;
unknown's avatar
unknown committed
136
    tables.alias = table_list->alias;
137

unknown's avatar
unknown committed
138
    table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
139
                                             MYF(MY_FAE | MY_ZEROFILL));
140 141
      if (select_lex->setup_ref_array(thd, order->elements) ||
	  setup_order(thd, select_lex->ref_pointer_array, &tables,
142 143
		      fields, all_fields, (ORDER*) order->first) ||
	  !(sortorder=make_unireg_sortorder((ORDER*) order->first, &length)) ||
unknown's avatar
unknown committed
144
	  (table->sort.found_records = filesort(thd, table, sortorder, length,
unknown's avatar
unknown committed
145
					   select, HA_POS_ERROR,
146 147
					   &examined_rows))
	  == HA_POS_ERROR)
148 149
    {
      delete select;
150
      free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
151
      DBUG_RETURN(TRUE);
152
    }
153 154 155 156 157 158
    /*
      Filesort has already found and selected the rows we want to delete,
      so we don't need the where clause
    */
    delete select;
    select= 0;
159 160
  }

unknown's avatar
unknown committed
161 162 163 164
  /* If quick select is used, initialize it before retrieving rows. */
  if (select && select->quick && select->quick->reset())
  {
    delete select;
165
    free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
166
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
167
  }
168
  init_read_record(&info,thd,table,select,1,1);
169
  deleted=0L;
170
  init_ftfuncs(thd, select_lex, 1);
unknown's avatar
unknown committed
171
  thd->proc_info="updating";
unknown's avatar
unknown committed
172 173
  while (!(error=info.read_record(&info)) && !thd->killed &&
	 !thd->net.report_error)
unknown's avatar
unknown committed
174
  {
unknown's avatar
unknown committed
175
    // thd->net.report_error is tested to disallow delete row on error
176
    if (!(select && select->skip_record())&& !thd->net.report_error )
unknown's avatar
unknown committed
177
    {
178

unknown's avatar
unknown committed
179 180 181 182 183 184 185
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        error= 1;
        break;
      }
186

unknown's avatar
unknown committed
187 188 189
      if (!(error=table->file->delete_row(table->record[0])))
      {
	deleted++;
unknown's avatar
unknown committed
190 191 192 193 194 195 196
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
        {
          error= 1;
          break;
        }
unknown's avatar
unknown committed
197 198 199 200 201 202 203 204 205
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
206 207 208 209 210 211 212 213 214
	/*
	  In < 4.0.14 we set the error number to 0 here, but that
	  was not sensible, because then MySQL would not roll back the
	  failed DELETE, and also wrote it to the binlog. For MyISAM
	  tables a DELETE probably never should fail (?), but for
	  InnoDB it can fail in a FOREIGN KEY error or an
	  out-of-tablespace error.
	*/
 	error= 1;
unknown's avatar
unknown committed
215 216 217
	break;
      }
    }
unknown's avatar
unknown committed
218 219
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
unknown's avatar
unknown committed
220
  }
221 222
  if (thd->killed && !error)
    error= 1;					// Aborted
unknown's avatar
unknown committed
223 224
  thd->proc_info="end";
  end_read_record(&info);
225
  free_io_cache(table);				// Will not do any harm
226
  if (options & OPTION_QUICK)
227
    (void) table->file->extra(HA_EXTRA_NORMAL);
228 229

cleanup:
unknown's avatar
unknown committed
230 231 232 233 234 235 236 237 238
  /*
    Invalidate the table in the query cache if something changed. This must
    be before binlog writing and ha_autocommit_...
  */
  if (deleted)
  {
    query_cache_invalidate3(thd, table_list, 1);
  }

unknown's avatar
unknown committed
239
  delete select;
240
  transactional_table= table->file->has_transactions();
241 242 243 244 245 246 247 248 249
  /*
    We write to the binary log even if we deleted no row, because maybe the
    user is using this command to ensure that a table is clean on master *and
    on slave*. Think of the case of a user having played separately with the
    master's table and slave's table and wanting to take a fresh identical
    start now.
    error < 0 means "really no error". error <= 0 means "maybe some error".
  */
  if ((deleted || (error < 0)) && (error <= 0 || !transactional_table))
unknown's avatar
unknown committed
250
  {
251 252
    if (mysql_bin_log.is_open())
    {
unknown's avatar
unknown committed
253 254
      if (error <= 0)
        thd->clear_error();
unknown's avatar
unknown committed
255
      Query_log_event qinfo(thd, thd->query, thd->query_length,
unknown's avatar
unknown committed
256
			    transactional_table, FALSE);
257
      if (mysql_bin_log.write(&qinfo) && transactional_table)
258
	error=1;
259
    }
unknown's avatar
unknown committed
260
    if (!transactional_table)
261
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
unknown's avatar
unknown committed
262
  }
unknown's avatar
unknown committed
263 264 265 266 267
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd,error >= 0))
      error=1;
  }
unknown's avatar
unknown committed
268

unknown's avatar
unknown committed
269 270 271 272 273
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
274
  free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
275
  if (error < 0)
unknown's avatar
unknown committed
276
  {
277
    thd->row_count_func= deleted;
278
    send_ok(thd,deleted);
unknown's avatar
unknown committed
279 280
    DBUG_PRINT("info",("%d records deleted",deleted));
  }
unknown's avatar
unknown committed
281
  DBUG_RETURN(error >= 0 || thd->net.report_error);
unknown's avatar
unknown committed
282 283 284 285 286 287 288 289 290
}


/*
  Prepare items in DELETE statement

  SYNOPSIS
    mysql_prepare_delete()
    thd			- thread handler
unknown's avatar
VIEW  
unknown committed
291
    table_list		- global/local table list
unknown's avatar
unknown committed
292 293 294
    conds		- conditions

  RETURN VALUE
unknown's avatar
unknown committed
295 296
    FALSE OK
    TRUE  error
unknown's avatar
unknown committed
297
*/
unknown's avatar
unknown committed
298
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
unknown's avatar
unknown committed
299
{
300
  SELECT_LEX *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
301
  DBUG_ENTER("mysql_prepare_delete");
unknown's avatar
unknown committed
302

303
  if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) ||
304
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
305
      setup_ftfuncs(select_lex))
unknown's avatar
unknown committed
306
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
307
  if (!table_list->updatable || check_key_in_view(thd, table_list))
unknown's avatar
unknown committed
308
  {
unknown's avatar
VIEW  
unknown committed
309
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
unknown's avatar
unknown committed
310
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
311
  }
312
  if (unique_table(table_list, table_list->next_global))
313
  {
314
    my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name);
unknown's avatar
unknown committed
315
    DBUG_RETURN(TRUE);
316
  }
unknown's avatar
VIEW  
unknown committed
317
  select_lex->fix_prepare_information(thd, conds);
unknown's avatar
unknown committed
318
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
319 320 321
}


322
/***************************************************************************
323
  Delete multiple tables from join 
324 325
***************************************************************************/

326
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
unknown's avatar
unknown committed
327

328
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
329
{
330 331
  handler *file= (handler*)arg;
  return file->cmp_ref((const byte*)a, (const byte*)b);
332
}
333

unknown's avatar
VIEW  
unknown committed
334 335 336 337 338 339 340 341
/*
  make delete specific preparation and checks after opening tables

  SYNOPSIS
    mysql_multi_delete_prepare()
    thd         thread handler

  RETURN
unknown's avatar
unknown committed
342 343
    FALSE OK
    TRUE  Error
unknown's avatar
VIEW  
unknown committed
344 345
*/

unknown's avatar
unknown committed
346
bool mysql_multi_delete_prepare(THD *thd)
unknown's avatar
VIEW  
unknown committed
347 348 349 350 351 352 353 354 355 356 357 358
{
  LEX *lex= thd->lex;
  TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxilliary_table_list.first;
  TABLE_LIST *target_tbl;
  DBUG_ENTER("mysql_multi_delete_prepare");

  /*
    setup_tables() need for VIEWs. JOIN::prepare() will not do it second
    time.

    lex->query_tables also point on local list of DELETE SELECT_LEX
  */
359
  if (setup_tables(thd, lex->query_tables, &lex->select_lex.where,
360
                   &lex->select_lex.leaf_tables, FALSE))
unknown's avatar
unknown committed
361
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
362

363 364 365 366 367 368

  /*
    Multi-delete can't be constructed over-union => we always have
    single SELECT on top and have to check underlying SELECTs of it
  */
  lex->select_lex.exclude_from_table_unique_test= TRUE;
unknown's avatar
VIEW  
unknown committed
369 370 371 372 373
  /* Fix tables-to-be-deleted-from list to point at opened tables */
  for (target_tbl= (TABLE_LIST*) aux_tables;
       target_tbl;
       target_tbl= target_tbl->next_local)
  {
374 375 376 377 378 379 380 381 382 383 384
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
    {
      DBUG_ASSERT(target_tbl->correspondent_table->view &&
                  target_tbl->correspondent_table->ancestor &&
                  target_tbl->correspondent_table->ancestor->next_local);
      my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
               target_tbl->correspondent_table->view_db.str,
               target_tbl->correspondent_table->view_name.str);
      DBUG_RETURN(TRUE);
    }

unknown's avatar
VIEW  
unknown committed
385 386 387
    if (!target_tbl->correspondent_table->updatable ||
        check_key_in_view(thd, target_tbl->correspondent_table))
    {
388
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
389
               target_tbl->table_name, "DELETE");
unknown's avatar
unknown committed
390
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
391 392
    }
    /*
393 394
      Check that table from which we delete is not used somewhere
      inside subqueries/view.
unknown's avatar
VIEW  
unknown committed
395
    */
396
    if (unique_table(target_tbl->correspondent_table, lex->query_tables))
unknown's avatar
VIEW  
unknown committed
397
    {
398 399 400
      my_error(ER_UPDATE_TABLE_USED, MYF(0),
               target_tbl->correspondent_table->table_name);
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
401 402
    }
  }
unknown's avatar
unknown committed
403
  DBUG_RETURN(FALSE);
unknown's avatar
VIEW  
unknown committed
404 405 406
}


unknown's avatar
unknown committed
407 408
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
			   uint num_of_tables_arg)
409
  : delete_tables(dt), thd(thd_arg), deleted(0), found(0),
unknown's avatar
unknown committed
410
    num_of_tables(num_of_tables_arg), error(0),
unknown's avatar
unknown committed
411
    do_delete(0), transactional_tables(0), normal_tables(0)
412
{
413
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
unknown's avatar
unknown committed
414 415 416 417
}


int
418
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
419 420
{
  DBUG_ENTER("multi_delete::prepare");
421
  unit= u;
unknown's avatar
unknown committed
422
  do_delete= 1;
unknown's avatar
unknown committed
423
  thd->proc_info="deleting from main table";
424 425 426
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
427

unknown's avatar
unknown committed
428
bool
unknown's avatar
unknown committed
429 430
multi_delete::initialize_tables(JOIN *join)
{
431
  TABLE_LIST *walk;
unknown's avatar
unknown committed
432 433 434 435 436 437
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

  if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
    DBUG_RETURN(1);

438
  table_map tables_to_delete_from=0;
unknown's avatar
VIEW  
unknown committed
439
  for (walk= delete_tables; walk; walk= walk->next_local)
440
    tables_to_delete_from|= walk->table->map;
unknown's avatar
unknown committed
441

442
  walk= delete_tables;
443
  delete_while_scanning= 1;
unknown's avatar
unknown committed
444 445 446 447
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
       tab < end;
       tab++)
  {
448
    if (tab->table->map & tables_to_delete_from)
unknown's avatar
unknown committed
449
    {
450
      /* We are going to delete from this table */
451
      TABLE *tbl=walk->table=tab->table;
unknown's avatar
VIEW  
unknown committed
452
      walk= walk->next_local;
unknown's avatar
unknown committed
453
      /* Don't use KEYREAD optimization on this table */
454
      tbl->no_keyread=1;
455 456
      /* Don't use record cache */
      tbl->no_cache= 1;
457
      tbl->used_keys.clear_all();
458
      if (tbl->file->has_transactions())
unknown's avatar
unknown committed
459
	transactional_tables= 1;
460 461
      else
	normal_tables= 1;
unknown's avatar
unknown committed
462
    }
463 464 465 466 467 468 469 470 471 472
    else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
             walk == delete_tables)
    {
      /*
        We are not deleting from the table we are scanning. In this
        case send_data() shouldn't delete any rows a we may touch
        the rows in the deleted table many times
      */
      delete_while_scanning= 0;
    }
unknown's avatar
unknown committed
473
  }
474
  walk= delete_tables;
unknown's avatar
unknown committed
475
  tempfiles_ptr= tempfiles;
476 477 478 479 480 481
  if (delete_while_scanning)
  {
    table_being_deleted= delete_tables;
    walk= walk->next_local;
  }
  for (;walk ;walk= walk->next_local)
482 483
  {
    TABLE *table=walk->table;
484 485
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
				  (void *) table->file,
unknown's avatar
unknown committed
486 487
				  table->file->ref_length,
				  MEM_STRIP_BUF_SIZE);
488
  }
unknown's avatar
unknown committed
489
  init_ftfuncs(thd, thd->lex->current_select, 1);
490
  DBUG_RETURN(thd->is_fatal_error != 0);
unknown's avatar
unknown committed
491
}
unknown's avatar
unknown committed
492

493

494 495
multi_delete::~multi_delete()
{
unknown's avatar
VIEW  
unknown committed
496 497 498
  for (table_being_deleted= delete_tables;
       table_being_deleted;
       table_being_deleted= table_being_deleted->next_local)
499
  {
500 501 502
    TABLE *table= table_being_deleted->table;
    free_io_cache(table);                       // Alloced by unique
    table->no_keyread=0;
503
  }
504

505
  for (uint counter= 0; counter < num_of_tables; counter++)
unknown's avatar
unknown committed
506
  {
507
    if (tempfiles[counter])
unknown's avatar
unknown committed
508 509
      delete tempfiles[counter];
  }
510 511
}

unknown's avatar
unknown committed
512

513 514
bool multi_delete::send_data(List<Item> &values)
{
515 516
  int secure_counter= delete_while_scanning ? -1 : 0;
  TABLE_LIST *del_table;
unknown's avatar
unknown committed
517 518
  DBUG_ENTER("multi_delete::send_data");

519 520 521
  for (del_table= delete_tables;
       del_table;
       del_table= del_table->next_local, secure_counter++)
522
  {
523
    TABLE *table= del_table->table;
unknown's avatar
unknown committed
524 525 526 527 528 529

    /* Check if we are using outer join and we didn't find the row */
    if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
      continue;

    table->file->position(table->record[0]);
530
    found++;
unknown's avatar
unknown committed
531

unknown's avatar
unknown committed
532
    if (secure_counter < 0)
533
    {
534 535
      /* We are scanning the current table */
      DBUG_ASSERT(del_table == table_being_deleted);
unknown's avatar
unknown committed
536 537 538 539
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
	DBUG_RETURN(1);
unknown's avatar
unknown committed
540 541
      table->status|= STATUS_DELETED;
      if (!(error=table->file->delete_row(table->record[0])))
unknown's avatar
unknown committed
542
      {
unknown's avatar
unknown committed
543
	deleted++;
unknown's avatar
unknown committed
544 545 546 547 548
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
	  DBUG_RETURN(1);
      }
549
      else
550
      {
unknown's avatar
unknown committed
551
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
552
	DBUG_RETURN(1);
unknown's avatar
unknown committed
553 554 555 556
      }
    }
    else
    {
unknown's avatar
unknown committed
557
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
unknown's avatar
unknown committed
558 559
      if (error)
      {
560
	error= 1;                               // Fatal error
unknown's avatar
unknown committed
561
	DBUG_RETURN(1);
unknown's avatar
unknown committed
562
      }
563 564
    }
  }
unknown's avatar
unknown committed
565
  DBUG_RETURN(0);
566 567
}

568

569 570
void multi_delete::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
571 572
  DBUG_ENTER("multi_delete::send_error");

unknown's avatar
unknown committed
573
  /* First send error what ever it is ... */
unknown's avatar
unknown committed
574
  my_message(errcode, err, MYF(0));
unknown's avatar
unknown committed
575

unknown's avatar
unknown committed
576 577
  /* If nothing deleted return */
  if (!deleted)
unknown's avatar
unknown committed
578
    DBUG_VOID_RETURN;
579

580
  /* Something already deleted so we have to invalidate cache */
581 582
  query_cache_invalidate3(thd, delete_tables, 1);

unknown's avatar
unknown committed
583
  /*
584 585
    If rows from the first table only has been deleted and it is
    transactional, just do rollback.
unknown's avatar
unknown committed
586 587 588
    The same if all tables are transactional, regardless of where we are.
    In all other cases do attempt deletes ...
  */
589 590 591
  if ((table_being_deleted == delete_tables &&
       table_being_deleted->table->file->has_transactions()) ||
      !normal_tables)
592
    ha_rollback_stmt(thd);
593
  else if (do_delete)
unknown's avatar
unknown committed
594
  {
595 596 597 598 599 600
    /*
      We have to execute the recorded do_deletes() and write info into the
      error log
    */
    error= 1;
    send_eof();
unknown's avatar
unknown committed
601 602
  }
  DBUG_VOID_RETURN;
603 604
}

unknown's avatar
unknown committed
605

unknown's avatar
unknown committed
606 607 608 609 610 611 612
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

613
int multi_delete::do_deletes()
614
{
615
  int local_error= 0, counter= 0;
616
  DBUG_ENTER("do_deletes");
617
  DBUG_ASSERT(do_delete);
unknown's avatar
unknown committed
618

619
  do_delete= 0;                                 // Mark called
620
  if (!found)
unknown's avatar
unknown committed
621
    DBUG_RETURN(0);
622 623 624 625 626

  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
                        delete_tables);
 
  for (; table_being_deleted;
unknown's avatar
VIEW  
unknown committed
627
       table_being_deleted= table_being_deleted->next_local, counter++)
628
  { 
unknown's avatar
unknown committed
629 630 631
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
632
      local_error=1;
unknown's avatar
unknown committed
633 634 635 636
      break;
    }

    READ_RECORD	info;
637 638 639 640 641 642
    init_read_record(&info,thd,table,NULL,0,1);
    /*
      Ignore any rows not found in reference tables as they may already have
      been deleted by foreign key handling
    */
    info.ignore_not_found_rows= 1;
unknown's avatar
merge  
unknown committed
643
    while (!(local_error=info.read_record(&info)) && !thd->killed)
unknown's avatar
unknown committed
644
    {
unknown's avatar
unknown committed
645 646 647 648 649 650 651
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        local_error= 1;
        break;
      }
652
      if ((local_error=table->file->delete_row(table->record[0])))
653
      {
654
	table->file->print_error(local_error,MYF(0));
unknown's avatar
unknown committed
655
	break;
656
      }
unknown's avatar
unknown committed
657
      deleted++;
unknown's avatar
unknown committed
658 659 660 661 662 663 664
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_AFTER, FALSE))
      {
        local_error= 1;
        break;
      }
665
    }
unknown's avatar
unknown committed
666
    end_read_record(&info);
667 668
    if (thd->killed && !local_error)
      local_error= 1;
669 670
    if (local_error == -1)				// End of file
      local_error = 0;
671
  }
672
  DBUG_RETURN(local_error);
673 674
}

unknown's avatar
unknown committed
675

676
/*
677 678
  Send ok to the client

679 680 681 682
  return:  0 sucess
	   1 error
*/

683 684
bool multi_delete::send_eof()
{
685
  thd->proc_info="deleting from reference tables";
686 687

  /* Does deletes for the last n - 1 tables, returns 0 if ok */
688
  int local_error= do_deletes();		// returns 0 if success
unknown's avatar
unknown committed
689

unknown's avatar
unknown committed
690
  /* reset used flags */
691
  thd->proc_info="end";
unknown's avatar
unknown committed
692

693 694 695 696
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
unknown's avatar
unknown committed
697
  if (deleted)
unknown's avatar
unknown committed
698
  {
unknown's avatar
unknown committed
699
    query_cache_invalidate3(thd, delete_tables, 1);
unknown's avatar
unknown committed
700
  }
unknown's avatar
unknown committed
701

702 703 704 705 706
  /*
    Write the SQL statement to the binlog if we deleted
    rows and we succeeded, or also in an error case when there
    was a non-transaction-safe table involved, since
    modifications in it cannot be rolled back.
707 708
    Note that if we deleted nothing we don't write to the binlog (TODO:
    fix this).
709
  */
710
  if (deleted && ((error <= 0 && !local_error) || normal_tables))
711
  {
unknown's avatar
unknown committed
712 713
    if (mysql_bin_log.is_open())
    {
714
      if (error <= 0 && !local_error)
unknown's avatar
unknown committed
715
        thd->clear_error();
716
      Query_log_event qinfo(thd, thd->query, thd->query_length,
unknown's avatar
unknown committed
717
			    transactional_tables, FALSE);
718
      if (mysql_bin_log.write(&qinfo) && !normal_tables)
719
	local_error=1;  // Log write failed: roll back the SQL statement
unknown's avatar
unknown committed
720
    }
unknown's avatar
unknown committed
721
    if (!transactional_tables)
unknown's avatar
unknown committed
722
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
723
  }
unknown's avatar
unknown committed
724
  /* Commit or rollback the current SQL statement */
unknown's avatar
unknown committed
725 726 727 728
  if (transactional_tables)
    if (ha_autocommit_or_rollback(thd,local_error > 0))
      local_error=1;

unknown's avatar
unknown committed
729
  if (!local_error)
730 731
  {
    thd->row_count_func= deleted;
unknown's avatar
unknown committed
732
    ::send_ok(thd, deleted);
733
  }
734 735
  return 0;
}
736 737 738


/***************************************************************************
739
  TRUNCATE TABLE
740 741 742 743 744 745 746 747 748 749 750
****************************************************************************/

/*
  Optimize delete of all rows by doing a full generate of the table
  This will work even if the .ISM and .ISD tables are destroyed

  dont_send_ok should be set if:
  - We should always wants to generate the table (even if the table type
    normally can't safely do this.
  - We don't want an ok to be sent to the end user.
  - We don't want to log the truncate command
unknown's avatar
unknown committed
751
  - If we want to have a name lock on the table on exit without errors.
752 753
*/

unknown's avatar
unknown committed
754
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
755 756 757 758
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
  TABLE **table_ptr;
unknown's avatar
unknown committed
759
  bool error;
760 761
  DBUG_ENTER("mysql_truncate");

762
  bzero((char*) &create_info,sizeof(create_info));
763
  /* If it is a temporary table, close and regenerate it */
unknown's avatar
unknown committed
764
  if (!dont_send_ok && (table_ptr=find_temporary_table(thd,table_list->db,
765
						       table_list->table_name)))
766 767 768
  {
    TABLE *table= *table_ptr;
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
769 770
    db_type table_type= table->s->db_type;
    strmov(path, table->s->path);
771 772 773 774
    *table_ptr= table->next;			// Unlink table from list
    close_temporary(table,0);
    *fn_ext(path)=0;				// Remove the .frm extension
    ha_create_table(path, &create_info,1);
unknown's avatar
unknown committed
775
    // We don't need to call invalidate() because this table is not in cache
776
    if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
777
					     table_list->table_name, 1))))
778
      (void) rm_temporary_table(table_type, path);
779
    /*
unknown's avatar
unknown committed
780 781
      If we return here we will not have logged the truncation to the bin log
      and we will not send_ok() to the client.
782
    */
unknown's avatar
unknown committed
783
    goto end;
784 785 786
  }

  (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
787
		 table_list->table_name,reg_ext);
788 789 790 791 792
  fn_format(path,path,"","",4);

  if (!dont_send_ok)
  {
    db_type table_type;
793
    if ((table_type=get_table_type(thd, path)) == DB_TYPE_UNKNOWN)
794
    {
795
      my_error(ER_NO_SUCH_TABLE, MYF(0),
796
               table_list->db, table_list->table_name);
unknown's avatar
unknown committed
797
      DBUG_RETURN(TRUE);
798
    }
799
    if (!ha_supports_generate(table_type) || thd->lex->sphead)
800 801
    {
      /* Probably InnoDB table */
802
      ulong save_options= thd->options;
unknown's avatar
unknown committed
803
      table_list->lock_type= TL_WRITE;
804
      thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
805
      ha_enable_transaction(thd, FALSE);
806
      mysql_init_select(thd->lex);
807 808 809
      error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
			  HA_POS_ERROR, 0);
      ha_enable_transaction(thd, TRUE);
810
      thd->options= save_options;
811
      DBUG_RETURN(error);
812 813
    }
    if (lock_and_wait_for_table_name(thd, table_list))
unknown's avatar
unknown committed
814
      DBUG_RETURN(TRUE);
815 816 817
  }

  *fn_ext(path)=0;				// Remove the .frm extension
unknown's avatar
unknown committed
818
  error= ha_create_table(path,&create_info,1);
unknown's avatar
unknown committed
819
  query_cache_invalidate3(thd, table_list, 0);
820

821
end:
unknown's avatar
unknown committed
822
  if (!dont_send_ok)
823
  {
unknown's avatar
unknown committed
824
    if (!error)
825
    {
unknown's avatar
unknown committed
826 827
      if (mysql_bin_log.is_open())
      {
unknown's avatar
unknown committed
828
        thd->clear_error();
829
	Query_log_event qinfo(thd, thd->query, thd->query_length,
unknown's avatar
unknown committed
830
			      0, FALSE);
unknown's avatar
unknown committed
831 832
	mysql_bin_log.write(&qinfo);
      }
833
      send_ok(thd);		// This should return record count
834
    }
835
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
836
    unlock_table_name(thd, table_list);
837
    VOID(pthread_mutex_unlock(&LOCK_open));
838
  }
unknown's avatar
unknown committed
839
  else if (error)
840 841
  {
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
842
    unlock_table_name(thd, table_list);
843 844
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
unknown's avatar
unknown committed
845
  DBUG_RETURN(error);
846
}