sql_delete.cc 30.6 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

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

unknown's avatar
unknown committed
43 44
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
45 46 47 48
  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
49
    DBUG_RETURN(TRUE);
50
  }
unknown's avatar
unknown committed
51 52
  thd->proc_info="init";
  table->map=1;
unknown's avatar
unknown committed
53

unknown's avatar
unknown committed
54 55
  if (mysql_prepare_delete(thd, table_list, &conds))
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
56

unknown's avatar
unknown committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
  /* 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);
    }
  }

78 79 80 81
  const_cond= (!conds || conds->const_item());
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
  if (safe_update && const_cond)
  {
unknown's avatar
unknown committed
82 83
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
84
    DBUG_RETURN(TRUE);
85 86
  }

87
  select_lex->no_error= thd->lex->ignore;
88

89 90 91 92
  /*
    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.
93 94 95 96 97 98 99 100 101 102 103 104 105 106

    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.
107
  */
unknown's avatar
unknown committed
108
  if (!using_limit && const_cond && (!conds || conds->val_int()) &&
109
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
110
      (thd->lex->sql_command == SQLCOM_TRUNCATE ||
111 112
       (!thd->current_stmt_binlog_row_based &&
        !(table->triggers && table->triggers->has_delete_triggers()))))
113
  {
114
    /* Update the table->file->stats.records number */
115
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
116
    ha_rows const maybe_deleted= table->file->stats.records;
117
    DBUG_PRINT("debug", ("Trying to use delete_all_rows()"));
118 119 120
    if (!(error=table->file->delete_all_rows()))
    {
      error= -1;				// ok
121
      deleted= maybe_deleted;
122 123 124 125 126 127 128 129 130 131
      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 */
  }
132 133 134 135 136 137 138
  if (conds)
  {
    Item::cond_result result;
    conds= remove_eq_conds(thd, conds, &result);
    if (result == Item::COND_FALSE)             // Impossible where
      limit= 0;
  }
139

140 141 142 143 144 145 146 147 148
#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (prune_partitions(thd, table, conds))
  {
    free_underlaid_joins(thd, select_lex);
    thd->row_count_func= 0;
    send_ok(thd);				// No matching records
    DBUG_RETURN(0);
  }
#endif
149
  /* Update the table->file->stats.records number */
150
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
151

152
  table->covering_keys.clear_all();
153
  table->quick_keys.clear_all();		// Can't use 'only index'
unknown's avatar
unknown committed
154
  select=make_select(table, 0, 0, conds, 0, &error);
unknown's avatar
unknown committed
155
  if (error)
unknown's avatar
unknown committed
156
    DBUG_RETURN(TRUE);
157
  if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
unknown's avatar
unknown committed
158 159
  {
    delete select;
160
    free_underlaid_joins(thd, select_lex);
161
    thd->row_count_func= 0;
162
    send_ok(thd,0L);
163 164 165 166 167
    /*
      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
168
    DBUG_RETURN(0);				// Nothing to delete
unknown's avatar
unknown committed
169 170 171
  }

  /* If running in safe sql mode, don't allow updates without keys */
172
  if (table->quick_keys.is_clear_all())
unknown's avatar
unknown committed
173
  {
174
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
unknown's avatar
unknown committed
175
    if (safe_update && !using_limit)
176 177
    {
      delete select;
178
      free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
179 180
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
181
      DBUG_RETURN(TRUE);
182
    }
unknown's avatar
unknown committed
183
  }
184
  if (options & OPTION_QUICK)
185 186
    (void) table->file->extra(HA_EXTRA_QUICK);

187
  if (order && order->elements)
188
  {
189
    uint         length= 0;
190
    SORT_FIELD  *sortorder;
191
    ha_rows examined_rows;
192
    
193
    if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
194 195 196 197 198 199 200
      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
201
      if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
202
                                             &length, NULL)) ||
unknown's avatar
unknown committed
203
	  (table->sort.found_records = filesort(thd, table, sortorder, length,
204
                                                select, HA_POS_ERROR, 1,
unknown's avatar
unknown committed
205
                                                &examined_rows))
206
	  == HA_POS_ERROR)
207 208 209
      {
        delete select;
        free_underlaid_joins(thd, &thd->lex->select_lex);
unknown's avatar
unknown committed
210
        DBUG_RETURN(TRUE);
211 212 213 214 215
      }
      /*
        Filesort has already found and selected the rows we want to delete,
        so we don't need the where clause
      */
216
      delete select;
217
      free_underlaid_joins(thd, select_lex);
218
      select= 0;
219 220 221
    }
  }

unknown's avatar
unknown committed
222 223 224 225
  /* If quick select is used, initialize it before retrieving rows. */
  if (select && select->quick && select->quick->reset())
  {
    delete select;
226
    free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
227
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
228
  }
229 230 231 232 233
  if (usable_index==MAX_KEY)
    init_read_record(&info,thd,table,select,1,1);
  else
    init_read_record_idx(&info, thd, table, 1, usable_index);

234
  init_ftfuncs(thd, select_lex, 1);
unknown's avatar
unknown committed
235
  thd->proc_info="updating";
236 237 238
  if (table->triggers && 
      table->triggers->has_triggers(TRG_EVENT_DELETE,
                                    TRG_ACTION_AFTER))
239
  {
240 241 242 243 244 245 246
    /*
      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;
247
  }
248 249
  else
    will_batch= !table->file->start_bulk_delete();
250 251


252 253
  table->mark_columns_needed_for_delete();

unknown's avatar
unknown committed
254 255
  while (!(error=info.read_record(&info)) && !thd->killed &&
	 !thd->net.report_error)
unknown's avatar
unknown committed
256
  {
unknown's avatar
unknown committed
257
    // thd->net.report_error is tested to disallow delete row on error
258
    if (!(select && select->skip_record())&& !thd->net.report_error )
unknown's avatar
unknown committed
259
    {
260

unknown's avatar
unknown committed
261 262 263 264 265 266 267
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        error= 1;
        break;
      }
268

269
      if (!(error= table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
270 271
      {
	deleted++;
unknown's avatar
unknown committed
272 273 274 275 276 277 278
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
        {
          error= 1;
          break;
        }
unknown's avatar
unknown committed
279 280 281 282 283 284 285 286 287
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
288 289 290 291 292 293 294 295 296
	/*
	  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
297 298 299
	break;
      }
    }
unknown's avatar
unknown committed
300 301
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
unknown's avatar
unknown committed
302
  }
303 304
  if (thd->killed && !error)
    error= 1;					// Aborted
unknown's avatar
unknown committed
305 306 307 308 309 310
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
  {
    if (error != 1)
      table->file->print_error(loc_error,MYF(0));
    error=1;
  }
unknown's avatar
unknown committed
311
  thd->proc_info= "end";
unknown's avatar
unknown committed
312
  end_read_record(&info);
313
  if (options & OPTION_QUICK)
314
    (void) table->file->extra(HA_EXTRA_NORMAL);
315

unknown's avatar
unknown committed
316
  if (reset_auto_increment && (error < 0))
317 318 319 320 321
  {
    /*
      We're really doing a truncate and need to reset the table's
      auto-increment counter.
    */
unknown's avatar
unknown committed
322
    int error2= table->file->reset_auto_increment(0);
323 324 325 326

    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
    {
      table->file->print_error(error2, MYF(0));
unknown's avatar
unknown committed
327
      error= 1;
328 329 330
    }
  }

331
cleanup:
unknown's avatar
unknown committed
332 333 334 335 336 337 338 339 340
  /*
    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
341
  delete select;
342
  transactional_table= table->file->has_transactions();
343

unknown's avatar
unknown committed
344 345 346
  if (!transactional_table && deleted > 0)
    thd->transaction.stmt.modified_non_trans_table= TRUE;
  
347
  /* See similar binlogging code in sql_update.cc, for comments */
348
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
unknown's avatar
unknown committed
349
  {
350 351
    if (mysql_bin_log.is_open())
    {
352
      if (error < 0)
unknown's avatar
unknown committed
353
        thd->clear_error();
354 355

      /*
356 357 358 359
        [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.
360
      */
361
      int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE,
362 363 364 365 366
                                        thd->query, thd->query_length,
                                        transactional_table, FALSE);

      if (log_result && transactional_table)
      {
367
	error=1;
368
      }
369
    }
unknown's avatar
unknown committed
370 371
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
372
  }
unknown's avatar
unknown committed
373
  DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
374
  free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
375 376 377 378 379
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd,error >= 0))
      error=1;
  }
unknown's avatar
unknown committed
380

unknown's avatar
unknown committed
381 382 383 384 385
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
386
  if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error))
unknown's avatar
unknown committed
387
  {
388
    thd->row_count_func= deleted;
389
    send_ok(thd,deleted);
unknown's avatar
unknown committed
390
    DBUG_PRINT("info",("%ld records deleted",(long) deleted));
unknown's avatar
unknown committed
391
  }
unknown's avatar
unknown committed
392
  DBUG_RETURN(error >= 0 || thd->net.report_error);
unknown's avatar
unknown committed
393 394 395 396 397 398 399 400 401
}


/*
  Prepare items in DELETE statement

  SYNOPSIS
    mysql_prepare_delete()
    thd			- thread handler
unknown's avatar
VIEW  
unknown committed
402
    table_list		- global/local table list
unknown's avatar
unknown committed
403 404 405
    conds		- conditions

  RETURN VALUE
unknown's avatar
unknown committed
406 407
    FALSE OK
    TRUE  error
unknown's avatar
unknown committed
408
*/
unknown's avatar
unknown committed
409
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
unknown's avatar
unknown committed
410
{
411
  Item *fake_conds= 0;
412
  SELECT_LEX *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
413
  DBUG_ENTER("mysql_prepare_delete");
414
  List<Item> all_fields;
unknown's avatar
unknown committed
415

unknown's avatar
unknown committed
416
  thd->lex->allow_sum_func= 0;
417 418
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
419
                                    table_list, 
420
                                    &select_lex->leaf_tables, FALSE, 
421
                                    DELETE_ACL, SELECT_ACL) ||
422
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
423
      setup_ftfuncs(select_lex))
unknown's avatar
unknown committed
424
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
425
  if (!table_list->updatable || check_key_in_view(thd, table_list))
unknown's avatar
unknown committed
426
  {
unknown's avatar
unknown committed
427
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
unknown's avatar
unknown committed
428
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
429
  }
430
  {
431
    TABLE_LIST *duplicate;
432
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
433
    {
unknown's avatar
unknown committed
434
      update_non_unique_table_error(table_list, "DELETE", duplicate);
435 436
      DBUG_RETURN(TRUE);
    }
437
  }
438 439 440 441 442

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

443
  select_lex->fix_prepare_information(thd, conds, &fake_conds);
unknown's avatar
unknown committed
444
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
445 446 447
}


448
/***************************************************************************
449
  Delete multiple tables from join 
450 451
***************************************************************************/

452
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
unknown's avatar
unknown committed
453

454
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
455
{
456
  handler *file= (handler*)arg;
457
  return file->cmp_ref((const uchar*)a, (const uchar*)b);
458
}
459

unknown's avatar
VIEW  
unknown committed
460 461 462 463 464 465 466 467
/*
  make delete specific preparation and checks after opening tables

  SYNOPSIS
    mysql_multi_delete_prepare()
    thd         thread handler

  RETURN
unknown's avatar
unknown committed
468 469
    FALSE OK
    TRUE  Error
unknown's avatar
VIEW  
unknown committed
470 471
*/

unknown's avatar
unknown committed
472
bool mysql_multi_delete_prepare(THD *thd)
unknown's avatar
VIEW  
unknown committed
473 474
{
  LEX *lex= thd->lex;
unknown's avatar
unknown committed
475
  TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first;
unknown's avatar
VIEW  
unknown committed
476 477 478 479 480 481 482 483 484
  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
  */
485 486
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
487
                                    lex->query_tables,
488
                                    &lex->select_lex.leaf_tables, FALSE, 
489
                                    DELETE_ACL, SELECT_ACL))
unknown's avatar
unknown committed
490
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
491

492 493 494 495 496 497

  /*
    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
498 499 500 501 502
  /* 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)
  {
503 504 505
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
    {
      DBUG_ASSERT(target_tbl->correspondent_table->view &&
506 507 508
                  target_tbl->correspondent_table->merge_underlying_list &&
                  target_tbl->correspondent_table->merge_underlying_list->
                  next_local);
509 510 511 512 513 514
      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
515 516 517
    if (!target_tbl->correspondent_table->updatable ||
        check_key_in_view(thd, target_tbl->correspondent_table))
    {
518
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
519
               target_tbl->table_name, "DELETE");
unknown's avatar
unknown committed
520
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
521 522
    }
    /*
523 524
      Check that table from which we delete is not used somewhere
      inside subqueries/view.
unknown's avatar
VIEW  
unknown committed
525 526
    */
    {
527
      TABLE_LIST *duplicate;
528
      if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
529
                                   lex->query_tables, 0)))
530 531 532 533 534
      {
        update_non_unique_table_error(target_tbl->correspondent_table,
                                      "DELETE", duplicate);
        DBUG_RETURN(TRUE);
      }
unknown's avatar
VIEW  
unknown committed
535 536
    }
  }
unknown's avatar
unknown committed
537
  DBUG_RETURN(FALSE);
unknown's avatar
VIEW  
unknown committed
538 539 540
}


541 542
multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
  : delete_tables(dt), deleted(0), found(0),
unknown's avatar
unknown committed
543
    num_of_tables(num_of_tables_arg), error(0),
544
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
545
{
546
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
unknown's avatar
unknown committed
547 548 549 550
}


int
551
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
552 553
{
  DBUG_ENTER("multi_delete::prepare");
554
  unit= u;
unknown's avatar
unknown committed
555
  do_delete= 1;
unknown's avatar
unknown committed
556
  thd->proc_info="deleting from main table";
557 558 559
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
560

unknown's avatar
unknown committed
561
bool
unknown's avatar
unknown committed
562 563
multi_delete::initialize_tables(JOIN *join)
{
564
  TABLE_LIST *walk;
unknown's avatar
unknown committed
565 566 567 568 569 570
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

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

571
  table_map tables_to_delete_from=0;
unknown's avatar
VIEW  
unknown committed
572
  for (walk= delete_tables; walk; walk= walk->next_local)
573
    tables_to_delete_from|= walk->table->map;
unknown's avatar
unknown committed
574

575
  walk= delete_tables;
576
  delete_while_scanning= 1;
unknown's avatar
unknown committed
577 578 579 580
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
       tab < end;
       tab++)
  {
581
    if (tab->table->map & tables_to_delete_from)
unknown's avatar
unknown committed
582
    {
583
      /* We are going to delete from this table */
584
      TABLE *tbl=walk->table=tab->table;
unknown's avatar
VIEW  
unknown committed
585
      walk= walk->next_local;
unknown's avatar
unknown committed
586
      /* Don't use KEYREAD optimization on this table */
587
      tbl->no_keyread=1;
588 589
      /* Don't use record cache */
      tbl->no_cache= 1;
590
      tbl->covering_keys.clear_all();
591
      if (tbl->file->has_transactions())
unknown's avatar
unknown committed
592
	transactional_tables= 1;
593 594
      else
	normal_tables= 1;
595 596
      if (tbl->triggers &&
          tbl->triggers->has_triggers(TRG_EVENT_DELETE,
597
                                      TRG_ACTION_AFTER))
598 599 600 601 602 603 604
      {
	/*
          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);
605
      }
606 607
      tbl->prepare_for_position();
      tbl->mark_columns_needed_for_delete();
unknown's avatar
unknown committed
608
    }
609 610 611 612 613 614 615 616 617 618
    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
619
  }
620
  walk= delete_tables;
unknown's avatar
unknown committed
621
  tempfiles_ptr= tempfiles;
622 623 624 625 626 627
  if (delete_while_scanning)
  {
    table_being_deleted= delete_tables;
    walk= walk->next_local;
  }
  for (;walk ;walk= walk->next_local)
628 629
  {
    TABLE *table=walk->table;
630 631
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
				  (void *) table->file,
unknown's avatar
unknown committed
632 633
				  table->file->ref_length,
				  MEM_STRIP_BUF_SIZE);
634
  }
unknown's avatar
unknown committed
635
  init_ftfuncs(thd, thd->lex->current_select, 1);
636
  DBUG_RETURN(thd->is_fatal_error != 0);
unknown's avatar
unknown committed
637
}
unknown's avatar
unknown committed
638

639

640 641
multi_delete::~multi_delete()
{
unknown's avatar
VIEW  
unknown committed
642 643 644
  for (table_being_deleted= delete_tables;
       table_being_deleted;
       table_being_deleted= table_being_deleted->next_local)
645
  {
646 647
    TABLE *table= table_being_deleted->table;
    table->no_keyread=0;
648
  }
649

650
  for (uint counter= 0; counter < num_of_tables; counter++)
unknown's avatar
unknown committed
651
  {
652
    if (tempfiles[counter])
unknown's avatar
unknown committed
653 654
      delete tempfiles[counter];
  }
655 656
}

unknown's avatar
unknown committed
657

658 659
bool multi_delete::send_data(List<Item> &values)
{
660 661
  int secure_counter= delete_while_scanning ? -1 : 0;
  TABLE_LIST *del_table;
unknown's avatar
unknown committed
662 663
  DBUG_ENTER("multi_delete::send_data");

664 665 666
  for (del_table= delete_tables;
       del_table;
       del_table= del_table->next_local, secure_counter++)
667
  {
668
    TABLE *table= del_table->table;
unknown's avatar
unknown committed
669 670 671 672 673 674

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

unknown's avatar
unknown committed
677
    if (secure_counter < 0)
678
    {
679 680
      /* We are scanning the current table */
      DBUG_ASSERT(del_table == table_being_deleted);
unknown's avatar
unknown committed
681 682 683
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
unknown's avatar
unknown committed
684
        DBUG_RETURN(1);
unknown's avatar
unknown committed
685
      table->status|= STATUS_DELETED;
686
      if (!(error=table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
687
      {
unknown's avatar
unknown committed
688 689 690
        deleted++;
        if (!table->file->has_transactions())
          thd->transaction.stmt.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
691 692 693
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
unknown's avatar
unknown committed
694
          DBUG_RETURN(1);
unknown's avatar
unknown committed
695
      }
696
      else
697
      {
unknown's avatar
unknown committed
698 699
        table->file->print_error(error,MYF(0));
        DBUG_RETURN(1);
unknown's avatar
unknown committed
700 701 702 703
      }
    }
    else
    {
unknown's avatar
unknown committed
704
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
unknown's avatar
unknown committed
705 706
      if (error)
      {
707
	error= 1;                               // Fatal error
unknown's avatar
unknown committed
708
	DBUG_RETURN(1);
unknown's avatar
unknown committed
709
      }
710 711
    }
  }
unknown's avatar
unknown committed
712
  DBUG_RETURN(0);
713 714
}

715

716 717
void multi_delete::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
718 719
  DBUG_ENTER("multi_delete::send_error");

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

723 724 725
  /* 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
726
    DBUG_VOID_RETURN;
727

728
  /* Something already deleted so we have to invalidate cache */
729 730
  if (deleted)
    query_cache_invalidate3(thd, delete_tables, 1);
731

unknown's avatar
unknown committed
732
  /*
733 734
    If rows from the first table only has been deleted and it is
    transactional, just do rollback.
unknown's avatar
unknown committed
735 736 737
    The same if all tables are transactional, regardless of where we are.
    In all other cases do attempt deletes ...
  */
738 739 740
  if ((table_being_deleted == delete_tables &&
       table_being_deleted->table->file->has_transactions()) ||
      !normal_tables)
741
    ha_rollback_stmt(thd);
742
  else if (do_delete)
unknown's avatar
unknown committed
743
  {
744 745 746 747 748 749
    /*
      We have to execute the recorded do_deletes() and write info into the
      error log
    */
    error= 1;
    send_eof();
750 751 752 753 754 755 756 757 758 759 760
    DBUG_ASSERT(error_handled);
    DBUG_VOID_RETURN;
  }
  
  if (thd->transaction.stmt.modified_non_trans_table)
  {
    /* 
       there is only side effects; to binlog with the error
    */
    if (mysql_bin_log.is_open())
    {
761 762 763
      thd->binlog_query(THD::ROW_QUERY_TYPE,
                        thd->query, thd->query_length,
                        transactional_tables, FALSE);
764 765
    }
    thd->transaction.all.modified_non_trans_table= true;
unknown's avatar
unknown committed
766
  }
unknown's avatar
unknown committed
767
  DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
unknown's avatar
unknown committed
768
  DBUG_VOID_RETURN;
769 770
}

unknown's avatar
unknown committed
771

772

unknown's avatar
unknown committed
773 774 775 776 777 778 779
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

780
int multi_delete::do_deletes()
781
{
782
  int local_error= 0, counter= 0, tmp_error;
unknown's avatar
unknown committed
783
  bool will_batch;
784
  DBUG_ENTER("do_deletes");
785
  DBUG_ASSERT(do_delete);
unknown's avatar
unknown committed
786

787
  do_delete= 0;                                 // Mark called
788
  if (!found)
unknown's avatar
unknown committed
789
    DBUG_RETURN(0);
790 791 792 793 794

  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
                        delete_tables);
 
  for (; table_being_deleted;
unknown's avatar
VIEW  
unknown committed
795
       table_being_deleted= table_being_deleted->next_local, counter++)
796
  { 
unknown's avatar
unknown committed
797
    ha_rows last_deleted= deleted;
unknown's avatar
unknown committed
798 799 800
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
801
      local_error=1;
unknown's avatar
unknown committed
802 803 804 805
      break;
    }

    READ_RECORD	info;
806 807 808 809 810 811
    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
unknown committed
812
    will_batch= !table->file->start_bulk_delete();
unknown's avatar
merge  
unknown committed
813
    while (!(local_error=info.read_record(&info)) && !thd->killed)
unknown's avatar
unknown committed
814
    {
unknown's avatar
unknown committed
815 816 817 818 819 820 821
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        local_error= 1;
        break;
      }
822
      if ((local_error=table->file->ha_delete_row(table->record[0])))
823
      {
824
	table->file->print_error(local_error,MYF(0));
unknown's avatar
unknown committed
825
	break;
826
      }
unknown's avatar
unknown committed
827
      deleted++;
unknown's avatar
unknown committed
828 829 830 831 832 833 834
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_AFTER, FALSE))
      {
        local_error= 1;
        break;
      }
835
    }
836
    if (will_batch && (tmp_error= table->file->end_bulk_delete()))
unknown's avatar
unknown committed
837 838 839
    {
      if (!local_error)
      {
840
        local_error= tmp_error;
unknown's avatar
unknown committed
841 842 843
        table->file->print_error(local_error,MYF(0));
      }
    }
unknown's avatar
unknown committed
844 845
    if (last_deleted != deleted && !table->file->has_transactions())
      thd->transaction.stmt.modified_non_trans_table= TRUE;
unknown's avatar
unknown committed
846
    end_read_record(&info);
847 848
    if (thd->killed && !local_error)
      local_error= 1;
849 850
    if (local_error == -1)				// End of file
      local_error = 0;
851
  }
852
  DBUG_RETURN(local_error);
853 854
}

unknown's avatar
unknown committed
855

856
/*
857 858
  Send ok to the client

859 860 861 862
  return:  0 sucess
	   1 error
*/

863 864
bool multi_delete::send_eof()
{
865
  thd->proc_info="deleting from reference tables";
866 867

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

870 871 872
  /* compute a total error to know if something failed */
  local_error= local_error || error;

unknown's avatar
unknown committed
873
  /* reset used flags */
874
  thd->proc_info="end";
unknown's avatar
unknown committed
875

876 877 878 879
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
unknown's avatar
unknown committed
880
  if (deleted)
unknown's avatar
unknown committed
881
  {
unknown's avatar
unknown committed
882
    query_cache_invalidate3(thd, delete_tables, 1);
unknown's avatar
unknown committed
883
  }
884 885
  DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
  if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
886
  {
unknown's avatar
unknown committed
887 888
    if (mysql_bin_log.is_open())
    {
889
      if (local_error == 0)
unknown's avatar
unknown committed
890
        thd->clear_error();
891 892 893 894 895
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
                            transactional_tables, FALSE) &&
          !normal_tables)
      {
896
	local_error=1;  // Log write failed: roll back the SQL statement
897
      }
unknown's avatar
unknown committed
898
    }
unknown's avatar
unknown committed
899 900
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
901
  }
902 903
  if (local_error != 0)
    error_handled= TRUE; // to force early leave from ::send_error()
unknown's avatar
unknown committed
904

unknown's avatar
unknown committed
905
  /* Commit or rollback the current SQL statement */
unknown's avatar
unknown committed
906 907 908 909
  if (transactional_tables)
    if (ha_autocommit_or_rollback(thd,local_error > 0))
      local_error=1;

unknown's avatar
unknown committed
910
  if (!local_error)
911 912
  {
    thd->row_count_func= deleted;
unknown's avatar
unknown committed
913
    ::send_ok(thd, deleted);
914
  }
915 916
  return 0;
}
917 918 919


/***************************************************************************
920
  TRUNCATE TABLE
921 922 923 924 925 926 927 928 929 930 931
****************************************************************************/

/*
  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
932
  - If we want to have a name lock on the table on exit without errors.
933 934
*/

unknown's avatar
unknown committed
935
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
936 937 938
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
unknown's avatar
unknown committed
939
  TABLE *table;
unknown's avatar
unknown committed
940
  bool error;
941
  uint path_length;
942 943
  DBUG_ENTER("mysql_truncate");

944
  bzero((char*) &create_info,sizeof(create_info));
945
  /* If it is a temporary table, close and regenerate it */
unknown's avatar
unknown committed
946
  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
947
  {
unknown's avatar
unknown committed
948
    handlerton *table_type= table->s->db_type();
unknown's avatar
unknown committed
949
    TABLE_SHARE *share= table->s;
950
    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
951
      goto trunc_by_del;
unknown's avatar
unknown committed
952 953 954 955 956 957

    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
958
    // We don't need to call invalidate() because this table is not in cache
unknown's avatar
unknown committed
959 960 961
    if ((error= (int) !(open_temporary_table(thd, share->path.str,
                                             share->db.str,
					     share->table_name.str, 1))))
962
      (void) rm_temporary_table(table_type, path);
unknown's avatar
unknown committed
963 964
    free_table_share(share);
    my_free((char*) table,MYF(0));
965
    /*
unknown's avatar
unknown committed
966 967
      If we return here we will not have logged the truncation to the bin log
      and we will not send_ok() to the client.
968
    */
unknown's avatar
unknown committed
969
    goto end;
970 971
  }

972
  path_length= build_table_filename(path, sizeof(path), table_list->db,
973
                                    table_list->table_name, reg_ext, 0);
974 975 976

  if (!dont_send_ok)
  {
unknown's avatar
unknown committed
977
    enum legacy_db_type table_type;
unknown's avatar
unknown committed
978
    mysql_frm_type(thd, path, &table_type);
979
    if (table_type == DB_TYPE_UNKNOWN)
980
    {
981
      my_error(ER_NO_SUCH_TABLE, MYF(0),
982
               table_list->db, table_list->table_name);
unknown's avatar
unknown committed
983
      DBUG_RETURN(TRUE);
984
    }
unknown's avatar
unknown committed
985
    if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
986
                                      HTON_CAN_RECREATE))
987
      goto trunc_by_del;
988

989
    if (lock_and_wait_for_table_name(thd, table_list))
unknown's avatar
unknown committed
990
      DBUG_RETURN(TRUE);
991 992
  }

993 994 995
  // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
  // crashes, replacement works.  *(path + path_length - reg_ext_length)=
  // '\0';
996
  path[path_length - reg_ext_length] = 0;
unknown's avatar
unknown committed
997
  VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
998 999
  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
                         &create_info, 1);
unknown's avatar
unknown committed
1000
  VOID(pthread_mutex_unlock(&LOCK_open));
unknown's avatar
unknown committed
1001
  query_cache_invalidate3(thd, table_list, 0);
1002

1003
end:
unknown's avatar
unknown committed
1004
  if (!dont_send_ok)
1005
  {
unknown's avatar
unknown committed
1006
    if (!error)
1007
    {
1008 1009 1010 1011 1012
      /*
        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);
1013
      send_ok(thd);		// This should return record count
1014
    }
1015
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
1016
    unlock_table_name(thd, table_list);
1017
    VOID(pthread_mutex_unlock(&LOCK_open));
1018
  }
unknown's avatar
unknown committed
1019
  else if (error)
1020 1021
  {
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
1022
    unlock_table_name(thd, table_list);
1023 1024
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
unknown's avatar
unknown committed
1025
  DBUG_RETURN(error);
1026

unknown's avatar
unknown committed
1027
trunc_by_del:
1028
  /* Probably InnoDB table */
1029
  ulonglong save_options= thd->options;
1030 1031 1032
  table_list->lock_type= TL_WRITE;
  thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
  ha_enable_transaction(thd, FALSE);
1033
  mysql_init_select(thd->lex);
1034
  bool save_binlog_row_based= thd->current_stmt_binlog_row_based;
1035
  thd->clear_current_stmt_binlog_row_based();
1036
  error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
1037
                      HA_POS_ERROR, LL(0), TRUE);
1038 1039
  ha_enable_transaction(thd, TRUE);
  thd->options= save_options;
1040
  thd->current_stmt_binlog_row_based= save_binlog_row_based;
1041
  DBUG_RETURN(error);
1042
}