sql_delete.cc 32.4 KB
Newer Older
1
/* Copyright (C) 2000 MySQL AB
unknown's avatar
unknown committed
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.
unknown's avatar
unknown committed
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.
unknown's avatar
unknown committed
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
  Delete of records and truncate of tables.
18

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

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

27 28 29 30 31 32 33 34
/**
  Implement DELETE SQL word.

  @note Like implementations of other DDL/DML in MySQL, this function
  relies on the caller to close the thread tables. This is done in the
  end of dispatch_command().
*/

unknown's avatar
unknown committed
35
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
unknown's avatar
unknown committed
36 37
                  SQL_LIST *order, ha_rows limit, ulonglong options,
                  bool reset_auto_increment)
unknown's avatar
unknown committed
38
{
unknown's avatar
unknown committed
39 40
  bool          will_batch;
  int		error, loc_error;
unknown's avatar
unknown committed
41
  TABLE		*table;
42
  SQL_SELECT	*select=0;
unknown's avatar
unknown committed
43
  READ_RECORD	info;
unknown's avatar
unknown committed
44 45
  bool          using_limit=limit != HA_POS_ERROR;
  bool		transactional_table, safe_update, const_cond;
46
  bool          const_cond_result;
47
  ha_rows	deleted= 0;
48
  bool          triggers_applicable;
49
  uint usable_index= MAX_KEY;
50
  SELECT_LEX   *select_lex= &thd->lex->select_lex;
51
  THD::killed_state killed_status= THD::NOT_KILLED;
unknown's avatar
unknown committed
52 53
  DBUG_ENTER("mysql_delete");

Mats Kindahl's avatar
Mats Kindahl committed
54 55 56 57 58
  THD::enum_binlog_query_type query_type=
    thd->lex->sql_command == SQLCOM_TRUNCATE ?
    THD::STMT_QUERY_TYPE :
    THD::ROW_QUERY_TYPE;

unknown's avatar
unknown committed
59 60
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
61 62 63 64
  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
65
    DBUG_RETURN(TRUE);
66
  }
67
  thd_proc_info(thd, "init");
unknown's avatar
unknown committed
68
  table->map=1;
unknown's avatar
unknown committed
69

unknown's avatar
unknown committed
70 71
  if (mysql_prepare_delete(thd, table_list, &conds))
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
72

unknown's avatar
unknown committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  /* check ORDER BY even if it can be ignored */
  if (order && order->elements)
  {
    TABLE_LIST   tables;
    List<Item>   fields;
    List<Item>   all_fields;

    bzero((char*) &tables,sizeof(tables));
    tables.table = table;
    tables.alias = table_list->alias;

      if (select_lex->setup_ref_array(thd, order->elements) ||
	  setup_order(thd, select_lex->ref_pointer_array, &tables,
                    fields, all_fields, (ORDER*) order->first))
    {
      delete select;
      free_underlaid_joins(thd, &thd->lex->select_lex);
      DBUG_RETURN(TRUE);
    }
  }

94 95 96 97
  const_cond= (!conds || conds->const_item());
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
  if (safe_update && const_cond)
  {
unknown's avatar
unknown committed
98 99
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
100
    DBUG_RETURN(TRUE);
101 102
  }

103
  select_lex->no_error= thd->lex->ignore;
104

105 106 107 108 109 110
  const_cond_result= const_cond && (!conds || conds->val_int());
  if (thd->is_error())
  {
    /* Error evaluating val_int(). */
    DBUG_RETURN(TRUE);
  }
111

112 113 114 115
  /*
    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.
116 117 118 119 120 121 122 123 124 125 126 127 128 129

    We implement fast TRUNCATE for InnoDB even if triggers are
    present.  TRUNCATE ignores triggers.

    We can use delete_all_rows() if and only if:
    - We allow new functions (not using option --skip-new), and are
      not in safe mode (not using option --safe-mode)
    - There is no limit clause
    - The condition is constant
    - If there is a condition, then it it produces a non-zero value
    - If the current command is DELETE FROM with no where clause
      (i.e., not TRUNCATE) then:
      - We should not be binlogging this statement row-based, and
      - there should be no delete triggers associated with the table.
130
  */
131
  if (!using_limit && const_cond_result &&
132
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
133
      (thd->lex->sql_command == SQLCOM_TRUNCATE ||
134 135
       (!thd->current_stmt_binlog_row_based &&
        !(table->triggers && table->triggers->has_delete_triggers()))))
136
  {
137
    /* Update the table->file->stats.records number */
138
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
139
    ha_rows const maybe_deleted= table->file->stats.records;
140
    DBUG_PRINT("debug", ("Trying to use delete_all_rows()"));
141
    if (!(error=table->file->ha_delete_all_rows()))
142
    {
Mats Kindahl's avatar
Mats Kindahl committed
143 144 145 146 147
      /*
        If delete_all_rows() is used, it is not possible to log the
        query in row format, so we have to log it in statement format.
      */
      query_type= THD::STMT_QUERY_TYPE;
148
      error= -1;				// ok
149
      deleted= maybe_deleted;
150 151 152 153 154 155 156 157 158 159
      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 */
  }
160 161 162 163 164 165 166
  if (conds)
  {
    Item::cond_result result;
    conds= remove_eq_conds(thd, conds, &result);
    if (result == Item::COND_FALSE)             // Impossible where
      limit= 0;
  }
167

168 169 170 171 172
#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (prune_partitions(thd, table, conds))
  {
    free_underlaid_joins(thd, select_lex);
    thd->row_count_func= 0;
173
    my_ok(thd, (ha_rows) thd->row_count_func);  // No matching records
174 175 176
    DBUG_RETURN(0);
  }
#endif
177
  /* Update the table->file->stats.records number */
178
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
179

180
  table->covering_keys.clear_all();
181
  table->quick_keys.clear_all();		// Can't use 'only index'
unknown's avatar
unknown committed
182
  select=make_select(table, 0, 0, conds, 0, &error);
unknown's avatar
unknown committed
183
  if (error)
unknown's avatar
unknown committed
184
    DBUG_RETURN(TRUE);
185
  if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
unknown's avatar
unknown committed
186 187
  {
    delete select;
188
    free_underlaid_joins(thd, select_lex);
189
    thd->row_count_func= 0;
190
    my_ok(thd, (ha_rows) thd->row_count_func);
191 192 193 194 195
    /*
      We don't need to call reset_auto_increment in this case, because
      mysql_truncate always gives a NULL conds argument, hence we never
      get here.
    */
unknown's avatar
unknown committed
196
    DBUG_RETURN(0);				// Nothing to delete
unknown's avatar
unknown committed
197 198 199
  }

  /* If running in safe sql mode, don't allow updates without keys */
200
  if (table->quick_keys.is_clear_all())
unknown's avatar
unknown committed
201
  {
202
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
unknown's avatar
unknown committed
203
    if (safe_update && !using_limit)
204 205
    {
      delete select;
206
      free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
207 208
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
209
      DBUG_RETURN(TRUE);
210
    }
unknown's avatar
unknown committed
211
  }
212
  if (options & OPTION_QUICK)
213 214
    (void) table->file->extra(HA_EXTRA_QUICK);

215
  if (order && order->elements)
216
  {
217
    uint         length= 0;
218
    SORT_FIELD  *sortorder;
219
    ha_rows examined_rows;
220
    
221
    if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
222 223 224 225 226 227 228
      usable_index= get_index_for_order(table, (ORDER*)(order->first), limit);

    if (usable_index == MAX_KEY)
    {
      table->sort.io_cache= (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
                                                   MYF(MY_FAE | MY_ZEROFILL));
    
unknown's avatar
unknown committed
229
      if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
230
                                             &length, NULL)) ||
unknown's avatar
unknown committed
231
	  (table->sort.found_records = filesort(thd, table, sortorder, length,
232
                                                select, HA_POS_ERROR, 1,
unknown's avatar
unknown committed
233
                                                &examined_rows))
234
	  == HA_POS_ERROR)
235 236 237
      {
        delete select;
        free_underlaid_joins(thd, &thd->lex->select_lex);
unknown's avatar
unknown committed
238
        DBUG_RETURN(TRUE);
239 240 241 242 243
      }
      /*
        Filesort has already found and selected the rows we want to delete,
        so we don't need the where clause
      */
244
      delete select;
245
      free_underlaid_joins(thd, select_lex);
246
      select= 0;
247 248 249
    }
  }

unknown's avatar
unknown committed
250 251 252 253
  /* If quick select is used, initialize it before retrieving rows. */
  if (select && select->quick && select->quick->reset())
  {
    delete select;
254
    free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
255
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
256
  }
257
  if (usable_index==MAX_KEY)
258
    init_read_record(&info, thd, table, select, 1, 1, FALSE);
259 260 261
  else
    init_read_record_idx(&info, thd, table, 1, usable_index);

262
  init_ftfuncs(thd, select_lex, 1);
263
  thd_proc_info(thd, "updating");
unknown's avatar
unknown committed
264 265 266 267 268 269

  /* NOTE: TRUNCATE must not invoke triggers. */

  triggers_applicable= table->triggers &&
                       thd->lex->sql_command != SQLCOM_TRUNCATE;

270
  if (triggers_applicable &&
271 272
      table->triggers->has_triggers(TRG_EVENT_DELETE,
                                    TRG_ACTION_AFTER))
273
  {
274 275 276 277 278 279 280
    /*
      The table has AFTER DELETE triggers that might access to subject table
      and therefore might need delete to be done immediately. So we turn-off
      the batching.
    */
    (void) table->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
    will_batch= FALSE;
281
  }
282 283
  else
    will_batch= !table->file->start_bulk_delete();
284 285


286 287
  table->mark_columns_needed_for_delete();

unknown's avatar
unknown committed
288
  while (!(error=info.read_record(&info)) && !thd->killed &&
289
	 ! thd->is_error())
unknown's avatar
unknown committed
290
  {
291 292
    // thd->is_error() is tested to disallow delete row on error
    if (!(select && select->skip_record())&& ! thd->is_error() )
unknown's avatar
unknown committed
293
    {
294

295
      if (triggers_applicable &&
unknown's avatar
unknown committed
296 297 298 299 300 301
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        error= 1;
        break;
      }
302

303
      if (!(error= table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
304 305
      {
	deleted++;
306
        if (triggers_applicable &&
unknown's avatar
unknown committed
307 308 309 310 311 312
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
        {
          error= 1;
          break;
        }
unknown's avatar
unknown committed
313 314 315 316 317 318 319 320 321
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
322 323 324 325 326 327 328 329 330
	/*
	  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
331 332 333
	break;
      }
    }
unknown's avatar
unknown committed
334 335
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
unknown's avatar
unknown committed
336
  }
337
  killed_status= thd->killed;
unknown's avatar
unknown committed
338
  if (killed_status != THD::NOT_KILLED || thd->is_error())
339
    error= 1;					// Aborted
unknown's avatar
unknown committed
340 341 342 343 344 345
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
  {
    if (error != 1)
      table->file->print_error(loc_error,MYF(0));
    error=1;
  }
346
  thd_proc_info(thd, "end");
unknown's avatar
unknown committed
347
  end_read_record(&info);
348
  if (options & OPTION_QUICK)
349
    (void) table->file->extra(HA_EXTRA_NORMAL);
350

unknown's avatar
unknown committed
351
  if (reset_auto_increment && (error < 0))
352 353 354 355 356
  {
    /*
      We're really doing a truncate and need to reset the table's
      auto-increment counter.
    */
357
    int error2= table->file->ha_reset_auto_increment(0);
358 359 360 361

    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
    {
      table->file->print_error(error2, MYF(0));
unknown's avatar
unknown committed
362
      error= 1;
363 364 365
    }
  }

366
cleanup:
unknown's avatar
unknown committed
367 368 369 370 371 372 373 374 375
  /*
    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
376
  delete select;
377
  transactional_table= table->file->has_transactions();
378

unknown's avatar
unknown committed
379 380 381
  if (!transactional_table && deleted > 0)
    thd->transaction.stmt.modified_non_trans_table= TRUE;
  
382
  /* See similar binlogging code in sql_update.cc, for comments */
383
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
unknown's avatar
unknown committed
384
  {
385 386
    if (mysql_bin_log.is_open())
    {
Mats Kindahl's avatar
Mats Kindahl committed
387 388 389 390 391
      bool const is_trans=
        thd->lex->sql_command == SQLCOM_TRUNCATE ?
        FALSE :
        transactional_table;

392
      if (error < 0)
unknown's avatar
unknown committed
393
        thd->clear_error();
394
      /*
395 396 397 398
        [binlog]: If 'handler::delete_all_rows()' was called and the
        storage engine does not inject the rows itself, we replicate
        statement-based; otherwise, 'ha_delete_row()' was used to
        delete specific rows which we might log row-based.
Mats Kindahl's avatar
Mats Kindahl committed
399 400 401

        Note that TRUNCATE TABLE is not transactional and should
        therefore be treated as a DDL.
402
      */
Mats Kindahl's avatar
Mats Kindahl committed
403
      int log_result= thd->binlog_query(query_type,
404
                                        thd->query, thd->query_length,
Mats Kindahl's avatar
Mats Kindahl committed
405
                                        is_trans, FALSE, killed_status);
406 407 408

      if (log_result && transactional_table)
      {
409
	error=1;
410
      }
411
    }
unknown's avatar
unknown committed
412 413
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
414
  }
unknown's avatar
unknown committed
415
  DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
416
  free_underlaid_joins(thd, select_lex);
417
  if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error))
unknown's avatar
unknown committed
418
  {
419 420 421 422 423
    /*
      If a TRUNCATE TABLE was issued, the number of rows should be reported as
      zero since the exact number is unknown.
    */
    thd->row_count_func= reset_auto_increment ? 0 : deleted;
424
    my_ok(thd, (ha_rows) thd->row_count_func);
unknown's avatar
unknown committed
425
    DBUG_PRINT("info",("%ld records deleted",(long) deleted));
unknown's avatar
unknown committed
426
  }
427
  DBUG_RETURN(error >= 0 || thd->is_error());
unknown's avatar
unknown committed
428 429 430 431 432 433 434 435 436
}


/*
  Prepare items in DELETE statement

  SYNOPSIS
    mysql_prepare_delete()
    thd			- thread handler
unknown's avatar
VIEW  
unknown committed
437
    table_list		- global/local table list
unknown's avatar
unknown committed
438 439 440
    conds		- conditions

  RETURN VALUE
unknown's avatar
unknown committed
441 442
    FALSE OK
    TRUE  error
unknown's avatar
unknown committed
443
*/
444
int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
unknown's avatar
unknown committed
445
{
446
  Item *fake_conds= 0;
447
  SELECT_LEX *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
448
  DBUG_ENTER("mysql_prepare_delete");
449
  List<Item> all_fields;
unknown's avatar
unknown committed
450

451 452 453 454 455 456 457 458 459 460 461 462 463
  /*
    Statement-based replication of DELETE ... LIMIT is not safe as order of
    rows is not defined, so in mixed mode we go to row-based.

    Note that we may consider a statement as safe if ORDER BY primary_key
    is present. However it may confuse users to see very similiar statements
    replicated differently.
  */
  if (thd->lex->current_select->select_limit)
  {
    thd->lex->set_stmt_unsafe();
    thd->set_current_stmt_binlog_row_based_if_mixed();
  }
unknown's avatar
unknown committed
464
  thd->lex->allow_sum_func= 0;
465 466
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
467
                                    table_list, 
468
                                    &select_lex->leaf_tables, FALSE, 
469
                                    DELETE_ACL, SELECT_ACL) ||
470
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
471
      setup_ftfuncs(select_lex))
unknown's avatar
unknown committed
472
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
473
  if (!table_list->updatable || check_key_in_view(thd, table_list))
unknown's avatar
unknown committed
474
  {
unknown's avatar
unknown committed
475
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
unknown's avatar
unknown committed
476
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
477
  }
478
  {
479
    TABLE_LIST *duplicate;
480
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
481
    {
unknown's avatar
unknown committed
482
      update_non_unique_table_error(table_list, "DELETE", duplicate);
483 484
      DBUG_RETURN(TRUE);
    }
485
  }
486 487 488 489 490

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

491
  select_lex->fix_prepare_information(thd, conds, &fake_conds);
unknown's avatar
unknown committed
492
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
493 494 495
}


496
/***************************************************************************
497
  Delete multiple tables from join 
498 499
***************************************************************************/

500
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
unknown's avatar
unknown committed
501

502
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
503
{
504
  handler *file= (handler*)arg;
505
  return file->cmp_ref((const uchar*)a, (const uchar*)b);
506
}
507

unknown's avatar
VIEW  
unknown committed
508 509 510 511 512 513 514 515
/*
  make delete specific preparation and checks after opening tables

  SYNOPSIS
    mysql_multi_delete_prepare()
    thd         thread handler

  RETURN
unknown's avatar
unknown committed
516 517
    FALSE OK
    TRUE  Error
unknown's avatar
VIEW  
unknown committed
518 519
*/

520
int mysql_multi_delete_prepare(THD *thd)
unknown's avatar
VIEW  
unknown committed
521 522
{
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
523
  TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first;
unknown's avatar
VIEW  
unknown committed
524 525 526 527 528 529 530 531 532
  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
  */
533 534
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
535
                                    lex->query_tables,
536
                                    &lex->select_lex.leaf_tables, FALSE, 
537
                                    DELETE_ACL, SELECT_ACL))
unknown's avatar
unknown committed
538
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
539

540 541 542 543 544 545

  /*
    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
546 547 548 549 550
  /* 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)
  {
551 552 553
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
    {
      DBUG_ASSERT(target_tbl->correspondent_table->view &&
554 555 556
                  target_tbl->correspondent_table->merge_underlying_list &&
                  target_tbl->correspondent_table->merge_underlying_list->
                  next_local);
557 558 559 560 561 562
      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
563 564 565
    if (!target_tbl->correspondent_table->updatable ||
        check_key_in_view(thd, target_tbl->correspondent_table))
    {
566
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
567
               target_tbl->table_name, "DELETE");
unknown's avatar
unknown committed
568
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
569 570
    }
    /*
571 572
      Check that table from which we delete is not used somewhere
      inside subqueries/view.
unknown's avatar
VIEW  
unknown committed
573 574
    */
    {
575
      TABLE_LIST *duplicate;
576
      if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
577
                                   lex->query_tables, 0)))
578 579 580 581 582
      {
        update_non_unique_table_error(target_tbl->correspondent_table,
                                      "DELETE", duplicate);
        DBUG_RETURN(TRUE);
      }
unknown's avatar
VIEW  
unknown committed
583 584
    }
  }
unknown's avatar
unknown committed
585
  DBUG_RETURN(FALSE);
unknown's avatar
VIEW  
unknown committed
586 587 588
}


589 590
multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
  : delete_tables(dt), deleted(0), found(0),
unknown's avatar
unknown committed
591
    num_of_tables(num_of_tables_arg), error(0),
592
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
593
{
594
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
unknown's avatar
unknown committed
595 596 597 598
}


int
599
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
600 601
{
  DBUG_ENTER("multi_delete::prepare");
602
  unit= u;
unknown's avatar
unknown committed
603
  do_delete= 1;
604
  thd_proc_info(thd, "deleting from main table");
605 606 607
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
608

unknown's avatar
unknown committed
609
bool
unknown's avatar
unknown committed
610 611
multi_delete::initialize_tables(JOIN *join)
{
612
  TABLE_LIST *walk;
unknown's avatar
unknown committed
613 614 615 616 617 618
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

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

619
  table_map tables_to_delete_from=0;
unknown's avatar
VIEW  
unknown committed
620
  for (walk= delete_tables; walk; walk= walk->next_local)
621
    tables_to_delete_from|= walk->table->map;
unknown's avatar
unknown committed
622

623
  walk= delete_tables;
624
  delete_while_scanning= 1;
unknown's avatar
unknown committed
625 626 627 628
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
       tab < end;
       tab++)
  {
629
    if (tab->table->map & tables_to_delete_from)
unknown's avatar
unknown committed
630
    {
631
      /* We are going to delete from this table */
632
      TABLE *tbl=walk->table=tab->table;
unknown's avatar
VIEW  
unknown committed
633
      walk= walk->next_local;
unknown's avatar
unknown committed
634
      /* Don't use KEYREAD optimization on this table */
635
      tbl->no_keyread=1;
636 637
      /* Don't use record cache */
      tbl->no_cache= 1;
638
      tbl->covering_keys.clear_all();
639
      if (tbl->file->has_transactions())
unknown's avatar
unknown committed
640
	transactional_tables= 1;
641 642
      else
	normal_tables= 1;
643 644
      if (tbl->triggers &&
          tbl->triggers->has_triggers(TRG_EVENT_DELETE,
645
                                      TRG_ACTION_AFTER))
646 647 648 649 650 651 652
      {
	/*
          The table has AFTER DELETE triggers that might access to subject 
          table and therefore might need delete to be done immediately. 
          So we turn-off the batching.
        */
	(void) tbl->file->extra(HA_EXTRA_DELETE_CANNOT_BATCH);
653
      }
654 655
      tbl->prepare_for_position();
      tbl->mark_columns_needed_for_delete();
unknown's avatar
unknown committed
656
    }
657 658 659 660 661 662 663 664 665 666
    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
667
  }
668
  walk= delete_tables;
unknown's avatar
unknown committed
669
  tempfiles_ptr= tempfiles;
670 671 672 673 674 675
  if (delete_while_scanning)
  {
    table_being_deleted= delete_tables;
    walk= walk->next_local;
  }
  for (;walk ;walk= walk->next_local)
676 677
  {
    TABLE *table=walk->table;
678 679
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
				  (void *) table->file,
unknown's avatar
unknown committed
680 681
				  table->file->ref_length,
				  MEM_STRIP_BUF_SIZE);
682
  }
unknown's avatar
unknown committed
683
  init_ftfuncs(thd, thd->lex->current_select, 1);
684
  DBUG_RETURN(thd->is_fatal_error != 0);
unknown's avatar
unknown committed
685
}
unknown's avatar
unknown committed
686

687

688 689
multi_delete::~multi_delete()
{
unknown's avatar
VIEW  
unknown committed
690 691 692
  for (table_being_deleted= delete_tables;
       table_being_deleted;
       table_being_deleted= table_being_deleted->next_local)
693
  {
694 695
    TABLE *table= table_being_deleted->table;
    table->no_keyread=0;
696
  }
697

698
  for (uint counter= 0; counter < num_of_tables; counter++)
unknown's avatar
unknown committed
699
  {
700
    if (tempfiles[counter])
unknown's avatar
unknown committed
701 702
      delete tempfiles[counter];
  }
703 704
}

unknown's avatar
unknown committed
705

706 707
bool multi_delete::send_data(List<Item> &values)
{
708 709
  int secure_counter= delete_while_scanning ? -1 : 0;
  TABLE_LIST *del_table;
unknown's avatar
unknown committed
710 711
  DBUG_ENTER("multi_delete::send_data");

712 713 714
  for (del_table= delete_tables;
       del_table;
       del_table= del_table->next_local, secure_counter++)
715
  {
716
    TABLE *table= del_table->table;
unknown's avatar
unknown committed
717 718 719 720 721 722

    /* 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]);
723
    found++;
unknown's avatar
unknown committed
724

unknown's avatar
unknown committed
725
    if (secure_counter < 0)
726
    {
727 728
      /* We are scanning the current table */
      DBUG_ASSERT(del_table == table_being_deleted);
unknown's avatar
unknown committed
729 730 731
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
unknown's avatar
unknown committed
732
        DBUG_RETURN(1);
unknown's avatar
unknown committed
733
      table->status|= STATUS_DELETED;
734
      if (!(error=table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
735
      {
unknown's avatar
unknown committed
736 737 738
        deleted++;
        if (!table->file->has_transactions())
          thd->transaction.stmt.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
739 740 741
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
unknown's avatar
unknown committed
742
          DBUG_RETURN(1);
unknown's avatar
unknown committed
743
      }
744
      else
745
      {
unknown's avatar
unknown committed
746 747
        table->file->print_error(error,MYF(0));
        DBUG_RETURN(1);
unknown's avatar
unknown committed
748 749 750 751
      }
    }
    else
    {
unknown's avatar
unknown committed
752
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
unknown's avatar
unknown committed
753 754
      if (error)
      {
755
	error= 1;                               // Fatal error
unknown's avatar
unknown committed
756
	DBUG_RETURN(1);
unknown's avatar
unknown committed
757
      }
758 759
    }
  }
unknown's avatar
unknown committed
760
  DBUG_RETURN(0);
761 762
}

763

764 765
void multi_delete::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
766 767
  DBUG_ENTER("multi_delete::send_error");

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

771 772 773 774 775 776 777 778
  DBUG_VOID_RETURN;
}


void multi_delete::abort()
{
  DBUG_ENTER("multi_delete::abort");

779 780 781
  /* the error was handled or nothing deleted and no side effects return */
  if (error_handled ||
      !thd->transaction.stmt.modified_non_trans_table && !deleted)
unknown's avatar
unknown committed
782
    DBUG_VOID_RETURN;
783

784
  /* Something already deleted so we have to invalidate cache */
785 786
  if (deleted)
    query_cache_invalidate3(thd, delete_tables, 1);
787

unknown's avatar
unknown committed
788
  /*
789 790
    If rows from the first table only has been deleted and it is
    transactional, just do rollback.
unknown's avatar
unknown committed
791 792 793
    The same if all tables are transactional, regardless of where we are.
    In all other cases do attempt deletes ...
  */
794 795 796
  if (do_delete && normal_tables &&
      (table_being_deleted != delete_tables ||
       !table_being_deleted->table->file->has_transactions()))
unknown's avatar
unknown committed
797
  {
798 799 800 801 802 803
    /*
      We have to execute the recorded do_deletes() and write info into the
      error log
    */
    error= 1;
    send_eof();
804 805
    DBUG_ASSERT(error_handled);
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
806
  }
807 808 809 810 811 812 813 814
  
  if (thd->transaction.stmt.modified_non_trans_table)
  {
    /* 
       there is only side effects; to binlog with the error
    */
    if (mysql_bin_log.is_open())
    {
815 816 817
      thd->binlog_query(THD::ROW_QUERY_TYPE,
                        thd->query, thd->query_length,
                        transactional_tables, FALSE);
818 819
    }
    thd->transaction.all.modified_non_trans_table= true;
unknown's avatar
unknown committed
820 821
  }
  DBUG_VOID_RETURN;
822 823
}

unknown's avatar
unknown committed
824

825

unknown's avatar
unknown committed
826 827 828 829 830 831 832
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

833
int multi_delete::do_deletes()
834
{
835
  int local_error= 0, counter= 0, tmp_error;
unknown's avatar
unknown committed
836
  bool will_batch;
837
  DBUG_ENTER("do_deletes");
838
  DBUG_ASSERT(do_delete);
unknown's avatar
unknown committed
839

840
  do_delete= 0;                                 // Mark called
841
  if (!found)
unknown's avatar
unknown committed
842
    DBUG_RETURN(0);
843 844 845 846 847

  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
                        delete_tables);
 
  for (; table_being_deleted;
unknown's avatar
VIEW  
unknown committed
848
       table_being_deleted= table_being_deleted->next_local, counter++)
849
  { 
unknown's avatar
unknown committed
850
    ha_rows last_deleted= deleted;
unknown's avatar
unknown committed
851 852 853
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
854
      local_error=1;
unknown's avatar
unknown committed
855 856 857 858
      break;
    }

    READ_RECORD	info;
859
    init_read_record(&info, thd, table, NULL, 0, 1, FALSE);
860 861 862 863 864
    /*
      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
unknown committed
865
    will_batch= !table->file->start_bulk_delete();
unknown's avatar
merge  
unknown committed
866
    while (!(local_error=info.read_record(&info)) && !thd->killed)
unknown's avatar
unknown committed
867
    {
unknown's avatar
unknown committed
868 869 870 871 872 873 874
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        local_error= 1;
        break;
      }
875
      if ((local_error=table->file->ha_delete_row(table->record[0])))
876
      {
877
	table->file->print_error(local_error,MYF(0));
unknown's avatar
unknown committed
878
	break;
879
      }
unknown's avatar
unknown committed
880
      deleted++;
unknown's avatar
unknown committed
881 882 883 884 885 886 887
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_AFTER, FALSE))
      {
        local_error= 1;
        break;
      }
888
    }
889
    if (will_batch && (tmp_error= table->file->end_bulk_delete()))
unknown's avatar
unknown committed
890 891 892
    {
      if (!local_error)
      {
893
        local_error= tmp_error;
unknown's avatar
unknown committed
894 895 896
        table->file->print_error(local_error,MYF(0));
      }
    }
unknown's avatar
unknown committed
897 898
    if (last_deleted != deleted && !table->file->has_transactions())
      thd->transaction.stmt.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
899
    end_read_record(&info);
900 901
    if (thd->killed && !local_error)
      local_error= 1;
902 903
    if (local_error == -1)				// End of file
      local_error = 0;
904
  }
905
  DBUG_RETURN(local_error);
906 907
}

unknown's avatar
unknown committed
908

909
/*
910 911
  Send ok to the client

912 913 914 915
  return:  0 sucess
	   1 error
*/

916 917
bool multi_delete::send_eof()
{
918
  THD::killed_state killed_status= THD::NOT_KILLED;
919
  thd_proc_info(thd, "deleting from reference tables");
920 921

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

924 925
  /* compute a total error to know if something failed */
  local_error= local_error || error;
926
  killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
unknown's avatar
unknown committed
927
  /* reset used flags */
928
  thd_proc_info(thd, "end");
unknown's avatar
unknown committed
929

930 931 932 933
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
unknown's avatar
unknown committed
934
  if (deleted)
unknown's avatar
unknown committed
935
  {
unknown's avatar
unknown committed
936
    query_cache_invalidate3(thd, delete_tables, 1);
unknown's avatar
unknown committed
937
  }
938
  if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
939
  {
unknown's avatar
unknown committed
940 941
    if (mysql_bin_log.is_open())
    {
942
      if (local_error == 0)
unknown's avatar
unknown committed
943
        thd->clear_error();
944 945
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
unknown's avatar
unknown committed
946
                            transactional_tables, FALSE, killed_status) &&
947 948
          !normal_tables)
      {
949
	local_error=1;  // Log write failed: roll back the SQL statement
950
      }
unknown's avatar
unknown committed
951
    }
unknown's avatar
unknown committed
952 953
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
954
  }
955 956
  if (local_error != 0)
    error_handled= TRUE; // to force early leave from ::send_error()
unknown's avatar
unknown committed
957

unknown's avatar
unknown committed
958
  if (!local_error)
959 960
  {
    thd->row_count_func= deleted;
961
    ::my_ok(thd, (ha_rows) thd->row_count_func);
962
  }
963 964
  return 0;
}
965 966 967


/***************************************************************************
968
  TRUNCATE TABLE
969 970
****************************************************************************/

971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
/*
  Row-by-row truncation if the engine does not support table recreation.
  Probably a InnoDB table.
*/

static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list)
{
  bool error, save_binlog_row_based= thd->current_stmt_binlog_row_based;
  DBUG_ENTER("mysql_truncate_by_delete");
  table_list->lock_type= TL_WRITE;
  mysql_init_select(thd->lex);
  thd->clear_current_stmt_binlog_row_based();
  error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE);
  ha_autocommit_or_rollback(thd, error);
  end_trans(thd, error ? ROLLBACK : COMMIT);
  thd->current_stmt_binlog_row_based= save_binlog_row_based;
  DBUG_RETURN(error);
}


991 992 993 994 995 996 997 998 999
/*
  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
1000
  - If we want to have a name lock on the table on exit without errors.
1001 1002
*/

unknown's avatar
unknown committed
1003
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
1004 1005 1006
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
unknown's avatar
unknown committed
1007
  TABLE *table;
unknown's avatar
unknown committed
1008
  bool error;
1009
  uint path_length;
1010 1011
  DBUG_ENTER("mysql_truncate");

1012
  bzero((char*) &create_info,sizeof(create_info));
1013
  /* If it is a temporary table, close and regenerate it */
unknown's avatar
unknown committed
1014
  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
1015
  {
unknown's avatar
unknown committed
1016
    handlerton *table_type= table->s->db_type();
unknown's avatar
unknown committed
1017
    TABLE_SHARE *share= table->s;
1018
    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
1019
      goto trunc_by_del;
unknown's avatar
unknown committed
1020 1021 1022 1023 1024 1025

    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
    
    close_temporary_table(thd, table, 0, 0);    // Don't free share
    ha_create_table(thd, share->normalized_path.str,
                    share->db.str, share->table_name.str, &create_info, 1);
unknown's avatar
unknown committed
1026
    // We don't need to call invalidate() because this table is not in cache
unknown's avatar
unknown committed
1027 1028 1029
    if ((error= (int) !(open_temporary_table(thd, share->path.str,
                                             share->db.str,
					     share->table_name.str, 1))))
1030
      (void) rm_temporary_table(table_type, path);
1031 1032 1033
    else
      thd->thread_specific_used= TRUE;
    
unknown's avatar
unknown committed
1034 1035
    free_table_share(share);
    my_free((char*) table,MYF(0));
1036
    /*
unknown's avatar
unknown committed
1037
      If we return here we will not have logged the truncation to the bin log
1038
      and we will not my_ok() to the client.
1039
    */
unknown's avatar
unknown committed
1040
    goto end;
1041 1042
  }

1043
  path_length= build_table_filename(path, sizeof(path), table_list->db,
1044
                                    table_list->table_name, reg_ext, 0);
1045 1046 1047

  if (!dont_send_ok)
  {
unknown's avatar
unknown committed
1048
    enum legacy_db_type table_type;
unknown's avatar
unknown committed
1049
    mysql_frm_type(thd, path, &table_type);
1050
    if (table_type == DB_TYPE_UNKNOWN)
1051
    {
1052
      my_error(ER_NO_SUCH_TABLE, MYF(0),
1053
               table_list->db, table_list->table_name);
unknown's avatar
unknown committed
1054
      DBUG_RETURN(TRUE);
1055
    }
unknown's avatar
unknown committed
1056
    if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
1057
                                      HTON_CAN_RECREATE))
1058
      goto trunc_by_del;
1059

1060
    if (lock_and_wait_for_table_name(thd, table_list))
unknown's avatar
unknown committed
1061
      DBUG_RETURN(TRUE);
1062 1063
  }

1064 1065 1066
  // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
  // crashes, replacement works.  *(path + path_length - reg_ext_length)=
  // '\0';
1067
  path[path_length - reg_ext_length] = 0;
unknown's avatar
unknown committed
1068
  VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
1069 1070
  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
                         &create_info, 1);
unknown's avatar
unknown committed
1071
  VOID(pthread_mutex_unlock(&LOCK_open));
unknown's avatar
unknown committed
1072
  query_cache_invalidate3(thd, table_list, 0);
1073

1074
end:
unknown's avatar
unknown committed
1075
  if (!dont_send_ok)
1076
  {
unknown's avatar
unknown committed
1077
    if (!error)
1078
    {
1079 1080 1081 1082 1083
      /*
        TRUNCATE must always be statement-based binlogged (not row-based) so
        we don't test current_stmt_binlog_row_based.
      */
      write_bin_log(thd, TRUE, thd->query, thd->query_length);
1084
      my_ok(thd);		// This should return record count
1085
    }
1086
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
1087
    unlock_table_name(thd, table_list);
1088
    VOID(pthread_mutex_unlock(&LOCK_open));
1089
  }
unknown's avatar
unknown committed
1090
  else if (error)
1091 1092
  {
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
1093
    unlock_table_name(thd, table_list);
1094 1095
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
unknown's avatar
unknown committed
1096
  DBUG_RETURN(error);
1097

unknown's avatar
unknown committed
1098
trunc_by_del:
1099
  error= mysql_truncate_by_delete(thd, table_list);
1100
  DBUG_RETURN(error);
1101
}