sql_delete.cc 26.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 17
   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 */

/*
18
  Delete of records and truncate of tables.
19

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

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

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

unknown's avatar
unknown committed
46 47
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
48 49 50 51
  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
52
    DBUG_RETURN(TRUE);
53
  }
54
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
unknown's avatar
unknown committed
55 56
  thd->proc_info="init";
  table->map=1;
unknown's avatar
unknown committed
57

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

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

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

72 73 74 75 76
  /*
    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
77
  if (!using_limit && const_cond && (!conds || conds->val_int()) &&
78 79
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
      !(table->triggers && table->triggers->has_delete_triggers()))
80
  {
81
    ha_rows const maybe_deleted= table->file->records;
82 83 84
    if (!(error=table->file->delete_all_rows()))
    {
      error= -1;				// ok
85 86
      deleted= maybe_deleted;
      ha_delete_row_bypassed= 1;
87 88 89 90 91
      goto cleanup;
    }
    if (error != HA_ERR_WRONG_COMMAND)
    {
      table->file->print_error(error,MYF(0));
92
      ha_delete_row_bypassed= 1;
93 94 95 96 97 98
      error=0;
      goto cleanup;
    }
    /* Handler didn't support fast delete; Delete rows one by one */
  }

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

    /*
      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
117
    DBUG_RETURN(0);				// Nothing to delete
unknown's avatar
unknown committed
118 119 120
  }

  /* If running in safe sql mode, don't allow updates without keys */
121
  if (table->quick_keys.is_clear_all())
unknown's avatar
unknown committed
122
  {
123
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
unknown's avatar
unknown committed
124
    if (safe_update && !using_limit)
125 126
    {
      delete select;
127
      free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
128 129
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
unknown's avatar
unknown committed
130
      DBUG_RETURN(TRUE);
131
    }
unknown's avatar
unknown committed
132
  }
133
  if (options & OPTION_QUICK)
134 135
    (void) table->file->extra(HA_EXTRA_QUICK);

136
  if (order && order->elements)
137 138 139 140 141 142
  {
    uint         length;
    SORT_FIELD  *sortorder;
    TABLE_LIST   tables;
    List<Item>   fields;
    List<Item>   all_fields;
143
    ha_rows examined_rows;
144 145 146

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

149 150
      if (select_lex->setup_ref_array(thd, order->elements) ||
	  setup_order(thd, select_lex->ref_pointer_array, &tables,
151 152 153 154
                    fields, all_fields, (ORDER*) order->first))
    {
      delete select;
      free_underlaid_joins(thd, &thd->lex->select_lex);
unknown's avatar
unknown committed
155
      DBUG_RETURN(TRUE);
156 157 158 159 160 161 162 163 164 165
    }
    
    if (!select && limit != HA_POS_ERROR)
      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
166 167
      if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
                                             &length)) ||
unknown's avatar
unknown committed
168
	  (table->sort.found_records = filesort(thd, table, sortorder, length,
unknown's avatar
unknown committed
169 170
                                                select, HA_POS_ERROR,
                                                &examined_rows))
171
	  == HA_POS_ERROR)
172 173 174
      {
        delete select;
        free_underlaid_joins(thd, &thd->lex->select_lex);
unknown's avatar
unknown committed
175
        DBUG_RETURN(TRUE);
176 177 178 179 180
      }
      /*
        Filesort has already found and selected the rows we want to delete,
        so we don't need the where clause
      */
181
      delete select;
182
      free_underlaid_joins(thd, select_lex);
183
      select= 0;
184 185 186
    }
  }

unknown's avatar
unknown committed
187 188 189 190
  /* If quick select is used, initialize it before retrieving rows. */
  if (select && select->quick && select->quick->reset())
  {
    delete select;
191
    free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
192
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
193
  }
194 195 196 197 198
  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);

199
  deleted=0L;
200
  init_ftfuncs(thd, select_lex, 1);
unknown's avatar
unknown committed
201
  thd->proc_info="updating";
unknown's avatar
unknown committed
202
  will_batch= !table->file->start_bulk_delete();
unknown's avatar
unknown committed
203 204
  while (!(error=info.read_record(&info)) && !thd->killed &&
	 !thd->net.report_error)
unknown's avatar
unknown committed
205
  {
unknown's avatar
unknown committed
206
    // thd->net.report_error is tested to disallow delete row on error
207
    if (!(select && select->skip_record())&& !thd->net.report_error )
unknown's avatar
unknown committed
208
    {
209

unknown's avatar
unknown committed
210 211 212 213 214 215 216
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        error= 1;
        break;
      }
217

218
      if (!(error= table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
219 220
      {
	deleted++;
unknown's avatar
unknown committed
221 222 223 224 225 226 227
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
        {
          error= 1;
          break;
        }
unknown's avatar
unknown committed
228 229 230 231 232 233 234 235 236
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
237 238 239 240 241 242 243 244 245
	/*
	  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
246 247 248
	break;
      }
    }
unknown's avatar
unknown committed
249 250
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
unknown's avatar
unknown committed
251
  }
252 253
  if (thd->killed && !error)
    error= 1;					// Aborted
unknown's avatar
unknown committed
254 255 256 257 258 259
  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
260
  thd->proc_info= "end";
unknown's avatar
unknown committed
261
  end_read_record(&info);
262
  free_io_cache(table);				// Will not do any harm
263
  if (options & OPTION_QUICK)
264
    (void) table->file->extra(HA_EXTRA_NORMAL);
265

unknown's avatar
unknown committed
266
  if (reset_auto_increment && (error < 0))
267 268 269 270 271
  {
    /*
      We're really doing a truncate and need to reset the table's
      auto-increment counter.
    */
unknown's avatar
unknown committed
272
    int error2= table->file->reset_auto_increment(0);
273 274 275 276

    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
    {
      table->file->print_error(error2, MYF(0));
unknown's avatar
unknown committed
277
      error= 1;
278 279 280
    }
  }

281
cleanup:
unknown's avatar
unknown committed
282 283 284 285 286 287 288 289 290
  /*
    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
291
  delete select;
292
  transactional_table= table->file->has_transactions();
293 294
  /* See similar binlogging code in sql_update.cc, for comments */
  if ((error < 0) || (deleted && !transactional_table))
unknown's avatar
unknown committed
295
  {
296 297
    if (mysql_bin_log.is_open())
    {
298
      if (error < 0)
unknown's avatar
unknown committed
299
        thd->clear_error();
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

      /*
        If 'handler::delete_all_rows()' was called, we replicate
        statement-based; otherwise, 'ha_delete_row()' was used to
        delete specific rows which we might log row-based.
      */
      THD::enum_binlog_query_type const
          query_type(ha_delete_row_bypassed ?
                     THD::STMT_QUERY_TYPE :
                     THD::ROW_QUERY_TYPE);
      int log_result= thd->binlog_query(query_type,
                                        thd->query, thd->query_length,
                                        transactional_table, FALSE);

      if (log_result && transactional_table)
      {
316
	error=1;
317
      }
318
    }
unknown's avatar
unknown committed
319
    if (!transactional_table)
320
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
unknown's avatar
unknown committed
321
  }
322
  free_underlaid_joins(thd, select_lex);
unknown's avatar
unknown committed
323 324 325 326 327
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd,error >= 0))
      error=1;
  }
unknown's avatar
unknown committed
328

unknown's avatar
unknown committed
329 330 331 332 333
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
unknown's avatar
unknown committed
334
  if (error < 0)
unknown's avatar
unknown committed
335
  {
336
    thd->row_count_func= deleted;
337
    send_ok(thd,deleted);
unknown's avatar
unknown committed
338 339
    DBUG_PRINT("info",("%d records deleted",deleted));
  }
unknown's avatar
unknown committed
340
  DBUG_RETURN(error >= 0 || thd->net.report_error);
unknown's avatar
unknown committed
341 342 343 344 345 346 347 348 349
}


/*
  Prepare items in DELETE statement

  SYNOPSIS
    mysql_prepare_delete()
    thd			- thread handler
unknown's avatar
VIEW  
unknown committed
350
    table_list		- global/local table list
unknown's avatar
unknown committed
351 352 353
    conds		- conditions

  RETURN VALUE
unknown's avatar
unknown committed
354 355
    FALSE OK
    TRUE  error
unknown's avatar
unknown committed
356
*/
unknown's avatar
unknown committed
357
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
unknown's avatar
unknown committed
358
{
359
  SELECT_LEX *select_lex= &thd->lex->select_lex;
unknown's avatar
unknown committed
360
  DBUG_ENTER("mysql_prepare_delete");
unknown's avatar
unknown committed
361

unknown's avatar
unknown committed
362
  thd->lex->allow_sum_func= 0;
363
  if (setup_tables(thd, &thd->lex->select_lex.context,
unknown's avatar
unknown committed
364
                   &thd->lex->select_lex.top_join_list,
365 366
                   table_list, conds, &select_lex->leaf_tables,
                   FALSE) ||
367
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
368
      setup_ftfuncs(select_lex))
unknown's avatar
unknown committed
369
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
370
  if (!table_list->updatable || check_key_in_view(thd, table_list))
unknown's avatar
unknown committed
371
  {
unknown's avatar
VIEW  
unknown committed
372
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
unknown's avatar
unknown committed
373
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
374
  }
375
  {
376
    TABLE_LIST *duplicate;
377
    if ((duplicate= unique_table(thd, table_list, table_list->next_global)))
378 379 380 381
    {
      update_non_unique_table_error(table_list, "DELETE", duplicate);
      DBUG_RETURN(TRUE);
    }
382
  }
unknown's avatar
VIEW  
unknown committed
383
  select_lex->fix_prepare_information(thd, conds);
unknown's avatar
unknown committed
384
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
385 386 387
}


388
/***************************************************************************
389
  Delete multiple tables from join 
390 391
***************************************************************************/

392
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
unknown's avatar
unknown committed
393

394
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
395
{
396 397
  handler *file= (handler*)arg;
  return file->cmp_ref((const byte*)a, (const byte*)b);
398
}
399

unknown's avatar
VIEW  
unknown committed
400 401 402 403 404 405 406 407
/*
  make delete specific preparation and checks after opening tables

  SYNOPSIS
    mysql_multi_delete_prepare()
    thd         thread handler

  RETURN
unknown's avatar
unknown committed
408 409
    FALSE OK
    TRUE  Error
unknown's avatar
VIEW  
unknown committed
410 411
*/

unknown's avatar
unknown committed
412
bool mysql_multi_delete_prepare(THD *thd)
unknown's avatar
VIEW  
unknown committed
413 414 415 416 417 418 419 420 421 422 423 424
{
  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
  */
425
  if (setup_tables(thd, &thd->lex->select_lex.context,
unknown's avatar
unknown committed
426
                   &thd->lex->select_lex.top_join_list,
427
                   lex->query_tables, &lex->select_lex.where,
428
                   &lex->select_lex.leaf_tables, FALSE))
unknown's avatar
unknown committed
429
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
430

431 432 433 434 435 436

  /*
    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
437 438 439 440 441
  /* 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)
  {
442 443 444
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
    {
      DBUG_ASSERT(target_tbl->correspondent_table->view &&
445 446 447
                  target_tbl->correspondent_table->merge_underlying_list &&
                  target_tbl->correspondent_table->merge_underlying_list->
                  next_local);
448 449 450 451 452 453
      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
454 455 456
    if (!target_tbl->correspondent_table->updatable ||
        check_key_in_view(thd, target_tbl->correspondent_table))
    {
457
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
458
               target_tbl->table_name, "DELETE");
unknown's avatar
unknown committed
459
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
460 461
    }
    /*
462 463
      Check that table from which we delete is not used somewhere
      inside subqueries/view.
unknown's avatar
VIEW  
unknown committed
464 465
    */
    {
466
      TABLE_LIST *duplicate;
467
      if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
468 469 470 471 472 473
                                   lex->query_tables)))
      {
        update_non_unique_table_error(target_tbl->correspondent_table,
                                      "DELETE", duplicate);
        DBUG_RETURN(TRUE);
      }
unknown's avatar
VIEW  
unknown committed
474 475
    }
  }
unknown's avatar
unknown committed
476
  DBUG_RETURN(FALSE);
unknown's avatar
VIEW  
unknown committed
477 478 479
}


480 481
multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
  : delete_tables(dt), deleted(0), found(0),
unknown's avatar
unknown committed
482
    num_of_tables(num_of_tables_arg), error(0),
unknown's avatar
unknown committed
483
    do_delete(0), transactional_tables(0), normal_tables(0)
484
{
485
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
unknown's avatar
unknown committed
486 487 488 489
}


int
490
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
unknown's avatar
unknown committed
491 492
{
  DBUG_ENTER("multi_delete::prepare");
493
  unit= u;
unknown's avatar
unknown committed
494
  do_delete= 1;
unknown's avatar
unknown committed
495
  thd->proc_info="deleting from main table";
496 497 498
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
499

unknown's avatar
unknown committed
500
bool
unknown's avatar
unknown committed
501 502
multi_delete::initialize_tables(JOIN *join)
{
503
  TABLE_LIST *walk;
unknown's avatar
unknown committed
504 505 506 507 508 509
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

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

510
  table_map tables_to_delete_from=0;
unknown's avatar
VIEW  
unknown committed
511
  for (walk= delete_tables; walk; walk= walk->next_local)
512
    tables_to_delete_from|= walk->table->map;
unknown's avatar
unknown committed
513

514
  walk= delete_tables;
515
  delete_while_scanning= 1;
unknown's avatar
unknown committed
516 517 518 519
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
       tab < end;
       tab++)
  {
520
    if (tab->table->map & tables_to_delete_from)
unknown's avatar
unknown committed
521
    {
522
      /* We are going to delete from this table */
523
      TABLE *tbl=walk->table=tab->table;
unknown's avatar
VIEW  
unknown committed
524
      walk= walk->next_local;
unknown's avatar
unknown committed
525
      /* Don't use KEYREAD optimization on this table */
526
      tbl->no_keyread=1;
527 528
      /* Don't use record cache */
      tbl->no_cache= 1;
529
      tbl->used_keys.clear_all();
530
      if (tbl->file->has_transactions())
unknown's avatar
unknown committed
531
	transactional_tables= 1;
532 533
      else
	normal_tables= 1;
unknown's avatar
unknown committed
534
    }
535 536 537 538 539 540 541 542 543 544
    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
545
  }
546
  walk= delete_tables;
unknown's avatar
unknown committed
547
  tempfiles_ptr= tempfiles;
548 549 550 551 552 553
  if (delete_while_scanning)
  {
    table_being_deleted= delete_tables;
    walk= walk->next_local;
  }
  for (;walk ;walk= walk->next_local)
554 555
  {
    TABLE *table=walk->table;
556 557
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
				  (void *) table->file,
unknown's avatar
unknown committed
558 559
				  table->file->ref_length,
				  MEM_STRIP_BUF_SIZE);
560
  }
unknown's avatar
unknown committed
561
  init_ftfuncs(thd, thd->lex->current_select, 1);
562
  DBUG_RETURN(thd->is_fatal_error != 0);
unknown's avatar
unknown committed
563
}
unknown's avatar
unknown committed
564

565

566 567
multi_delete::~multi_delete()
{
unknown's avatar
VIEW  
unknown committed
568 569 570
  for (table_being_deleted= delete_tables;
       table_being_deleted;
       table_being_deleted= table_being_deleted->next_local)
571
  {
572 573 574
    TABLE *table= table_being_deleted->table;
    free_io_cache(table);                       // Alloced by unique
    table->no_keyread=0;
575
  }
576

577
  for (uint counter= 0; counter < num_of_tables; counter++)
unknown's avatar
unknown committed
578
  {
579
    if (tempfiles[counter])
unknown's avatar
unknown committed
580 581
      delete tempfiles[counter];
  }
582 583
}

unknown's avatar
unknown committed
584

585 586
bool multi_delete::send_data(List<Item> &values)
{
587 588
  int secure_counter= delete_while_scanning ? -1 : 0;
  TABLE_LIST *del_table;
unknown's avatar
unknown committed
589 590
  DBUG_ENTER("multi_delete::send_data");

591 592 593
  for (del_table= delete_tables;
       del_table;
       del_table= del_table->next_local, secure_counter++)
594
  {
595
    TABLE *table= del_table->table;
unknown's avatar
unknown committed
596 597 598 599 600 601

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

unknown's avatar
unknown committed
604
    if (secure_counter < 0)
605
    {
606 607
      /* We are scanning the current table */
      DBUG_ASSERT(del_table == table_being_deleted);
unknown's avatar
unknown committed
608 609 610 611
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
	DBUG_RETURN(1);
unknown's avatar
unknown committed
612
      table->status|= STATUS_DELETED;
613
      if (!(error=table->file->ha_delete_row(table->record[0])))
unknown's avatar
unknown committed
614
      {
unknown's avatar
unknown committed
615
	deleted++;
unknown's avatar
unknown committed
616 617 618 619 620
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
	  DBUG_RETURN(1);
      }
621
      else
622
      {
unknown's avatar
unknown committed
623
	table->file->print_error(error,MYF(0));
unknown's avatar
unknown committed
624
	DBUG_RETURN(1);
unknown's avatar
unknown committed
625 626 627 628
      }
    }
    else
    {
unknown's avatar
unknown committed
629
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
unknown's avatar
unknown committed
630 631
      if (error)
      {
632
	error= 1;                               // Fatal error
unknown's avatar
unknown committed
633
	DBUG_RETURN(1);
unknown's avatar
unknown committed
634
      }
635 636
    }
  }
unknown's avatar
unknown committed
637
  DBUG_RETURN(0);
638 639
}

640

641 642
void multi_delete::send_error(uint errcode,const char *err)
{
unknown's avatar
unknown committed
643 644
  DBUG_ENTER("multi_delete::send_error");

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

unknown's avatar
unknown committed
648 649
  /* If nothing deleted return */
  if (!deleted)
unknown's avatar
unknown committed
650
    DBUG_VOID_RETURN;
651

652
  /* Something already deleted so we have to invalidate cache */
653 654
  query_cache_invalidate3(thd, delete_tables, 1);

unknown's avatar
unknown committed
655
  /*
656 657
    If rows from the first table only has been deleted and it is
    transactional, just do rollback.
unknown's avatar
unknown committed
658 659 660
    The same if all tables are transactional, regardless of where we are.
    In all other cases do attempt deletes ...
  */
661 662 663
  if ((table_being_deleted == delete_tables &&
       table_being_deleted->table->file->has_transactions()) ||
      !normal_tables)
664
    ha_rollback_stmt(thd);
665
  else if (do_delete)
unknown's avatar
unknown committed
666
  {
667 668 669 670 671 672
    /*
      We have to execute the recorded do_deletes() and write info into the
      error log
    */
    error= 1;
    send_eof();
unknown's avatar
unknown committed
673 674
  }
  DBUG_VOID_RETURN;
675 676
}

unknown's avatar
unknown committed
677

unknown's avatar
unknown committed
678 679 680 681 682 683 684
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

685
int multi_delete::do_deletes()
686
{
unknown's avatar
unknown committed
687 688
  int local_error= 0, counter= 0, error;
  bool will_batch;
689
  DBUG_ENTER("do_deletes");
690
  DBUG_ASSERT(do_delete);
unknown's avatar
unknown committed
691

692
  do_delete= 0;                                 // Mark called
693
  if (!found)
unknown's avatar
unknown committed
694
    DBUG_RETURN(0);
695 696 697 698 699

  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
                        delete_tables);
 
  for (; table_being_deleted;
unknown's avatar
VIEW  
unknown committed
700
       table_being_deleted= table_being_deleted->next_local, counter++)
701
  { 
unknown's avatar
unknown committed
702 703 704
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
705
      local_error=1;
unknown's avatar
unknown committed
706 707 708 709
      break;
    }

    READ_RECORD	info;
710 711 712 713 714 715
    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
716
    will_batch= !table->file->start_bulk_delete();
unknown's avatar
merge  
unknown committed
717
    while (!(local_error=info.read_record(&info)) && !thd->killed)
unknown's avatar
unknown committed
718
    {
unknown's avatar
unknown committed
719 720 721 722 723 724 725
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        local_error= 1;
        break;
      }
726
      if ((local_error=table->file->ha_delete_row(table->record[0])))
727
      {
728
	table->file->print_error(local_error,MYF(0));
unknown's avatar
unknown committed
729
	break;
730
      }
unknown's avatar
unknown committed
731
      deleted++;
unknown's avatar
unknown committed
732 733 734 735 736 737 738
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_AFTER, FALSE))
      {
        local_error= 1;
        break;
      }
739
    }
unknown's avatar
unknown committed
740
    if (will_batch && (error= table->file->end_bulk_delete()))
unknown's avatar
unknown committed
741 742 743 744 745 746 747
    {
      if (!local_error)
      {
        local_error= error;
        table->file->print_error(local_error,MYF(0));
      }
    }
unknown's avatar
unknown committed
748
    end_read_record(&info);
749 750
    if (thd->killed && !local_error)
      local_error= 1;
751 752
    if (local_error == -1)				// End of file
      local_error = 0;
753
  }
754
  DBUG_RETURN(local_error);
755 756
}

unknown's avatar
unknown committed
757

758
/*
759 760
  Send ok to the client

761 762 763 764
  return:  0 sucess
	   1 error
*/

765 766
bool multi_delete::send_eof()
{
767
  thd->proc_info="deleting from reference tables";
768 769

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

772 773 774
  /* compute a total error to know if something failed */
  local_error= local_error || error;

unknown's avatar
unknown committed
775
  /* reset used flags */
776
  thd->proc_info="end";
unknown's avatar
unknown committed
777

778 779 780 781
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
unknown's avatar
unknown committed
782
  if (deleted)
unknown's avatar
unknown committed
783
  {
unknown's avatar
unknown committed
784
    query_cache_invalidate3(thd, delete_tables, 1);
unknown's avatar
unknown committed
785
  }
unknown's avatar
unknown committed
786

787
  if ((local_error == 0) || (deleted && normal_tables))
788
  {
unknown's avatar
unknown committed
789 790
    if (mysql_bin_log.is_open())
    {
791
      if (local_error == 0)
unknown's avatar
unknown committed
792
        thd->clear_error();
793 794 795 796 797
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
                            transactional_tables, FALSE) &&
          !normal_tables)
      {
798
	local_error=1;  // Log write failed: roll back the SQL statement
799
      }
unknown's avatar
unknown committed
800
    }
unknown's avatar
unknown committed
801
    if (!transactional_tables)
unknown's avatar
unknown committed
802
      thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
803
  }
unknown's avatar
unknown committed
804
  /* Commit or rollback the current SQL statement */
unknown's avatar
unknown committed
805 806 807 808
  if (transactional_tables)
    if (ha_autocommit_or_rollback(thd,local_error > 0))
      local_error=1;

unknown's avatar
unknown committed
809
  if (!local_error)
810 811
  {
    thd->row_count_func= deleted;
unknown's avatar
unknown committed
812
    ::send_ok(thd, deleted);
813
  }
814 815
  return 0;
}
816 817 818


/***************************************************************************
819
  TRUNCATE TABLE
820 821 822 823 824 825 826 827 828 829 830
****************************************************************************/

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

unknown's avatar
unknown committed
834
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
835 836 837
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
unknown's avatar
unknown committed
838
  TABLE *table;
unknown's avatar
unknown committed
839
  bool error;
840
  uint path_length;
841 842
  DBUG_ENTER("mysql_truncate");

843
  bzero((char*) &create_info,sizeof(create_info));
844
  /* If it is a temporary table, close and regenerate it */
unknown's avatar
unknown committed
845
  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
846
  {
unknown's avatar
unknown committed
847
    handlerton *table_type= table->s->db_type;
unknown's avatar
unknown committed
848
    TABLE_SHARE *share= table->s;
849
    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
850
      goto trunc_by_del;
unknown's avatar
unknown committed
851 852 853 854 855 856

    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
857
    // We don't need to call invalidate() because this table is not in cache
unknown's avatar
unknown committed
858 859 860
    if ((error= (int) !(open_temporary_table(thd, share->path.str,
                                             share->db.str,
					     share->table_name.str, 1))))
861
      (void) rm_temporary_table(table_type, path);
unknown's avatar
unknown committed
862 863
    free_table_share(share);
    my_free((char*) table,MYF(0));
864
    /*
unknown's avatar
unknown committed
865 866
      If we return here we will not have logged the truncation to the bin log
      and we will not send_ok() to the client.
867
    */
unknown's avatar
unknown committed
868
    goto end;
869 870
  }

871 872
  path_length= build_table_filename(path, sizeof(path), table_list->db,
                                    table_list->table_name, reg_ext);
873 874 875

  if (!dont_send_ok)
  {
unknown's avatar
unknown committed
876
    enum legacy_db_type table_type;
877 878
    mysql_frm_type(thd, path, &table_type);
    if (table_type == DB_TYPE_UNKNOWN)
879
    {
880
      my_error(ER_NO_SUCH_TABLE, MYF(0),
881
               table_list->db, table_list->table_name);
unknown's avatar
unknown committed
882
      DBUG_RETURN(TRUE);
883
    }
unknown's avatar
unknown committed
884 885
    if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
                                      HTON_CAN_RECREATE)
886
        || thd->lex->sphead)
887
      goto trunc_by_del;
888
    if (lock_and_wait_for_table_name(thd, table_list))
unknown's avatar
unknown committed
889
      DBUG_RETURN(TRUE);
890 891
  }

892
  // Remove the .frm extension
893 894 895
  // AIX 5.2 64-bit compiler bug (BUG#16155): this crashes, replacement works.
  //   *(path + path_length - reg_ext_length)= '\0';
  path[path_length - reg_ext_length] = 0;
unknown's avatar
unknown committed
896 897
  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
                         &create_info, 1);
unknown's avatar
unknown committed
898
  query_cache_invalidate3(thd, table_list, 0);
899

900
end:
unknown's avatar
unknown committed
901
  if (!dont_send_ok)
902
  {
unknown's avatar
unknown committed
903
    if (!error)
904
    {
unknown's avatar
unknown committed
905 906
      if (mysql_bin_log.is_open())
      {
907 908 909 910
        /*
          TRUNCATE must always be statement-based binlogged (not row-based) so
          we don't test binlog_row_based.
        */
unknown's avatar
unknown committed
911
        thd->clear_error();
912 913
        thd->binlog_query(THD::STMT_QUERY_TYPE,
                          thd->query, thd->query_length, FALSE, FALSE);
unknown's avatar
unknown committed
914
      }
915
      send_ok(thd);		// This should return record count
916
    }
917
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
918
    unlock_table_name(thd, table_list);
919
    VOID(pthread_mutex_unlock(&LOCK_open));
920
  }
unknown's avatar
unknown committed
921
  else if (error)
922 923
  {
    VOID(pthread_mutex_lock(&LOCK_open));
unknown's avatar
unknown committed
924
    unlock_table_name(thd, table_list);
925 926
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
unknown's avatar
unknown committed
927
  DBUG_RETURN(error);
928

unknown's avatar
unknown committed
929
trunc_by_del:
930 931 932 933 934
  /* Probably InnoDB table */
  ulong save_options= thd->options;
  table_list->lock_type= TL_WRITE;
  thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
  ha_enable_transaction(thd, FALSE);
935
  mysql_init_select(thd->lex);
936
  error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
937
                      HA_POS_ERROR, LL(0), TRUE);
938 939 940
  ha_enable_transaction(thd, TRUE);
  thd->options= save_options;
  DBUG_RETURN(error);
941
}