sql_delete.cc 31.1 KB
Newer Older
1
/* Copyright (C) 2000 MySQL AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com 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
5
   the Free Software Foundation; version 2 of the License.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
6

bk@work.mysql.com's avatar
bk@work.mysql.com 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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
11

bk@work.mysql.com's avatar
bk@work.mysql.com 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
bk@work.mysql.com's avatar
bk@work.mysql.com committed
20 21
*/

22 23
#include "mysql_priv.h"
#include "sql_select.h"
24 25
#include "sp_head.h"
#include "sql_trigger.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26

27
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
osku@127.(none)'s avatar
osku@127.(none) committed
28 29
                  SQL_LIST *order, ha_rows limit, ulonglong options,
                  bool reset_auto_increment)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
30
{
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
31 32
  bool          will_batch;
  int		error, loc_error;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
33
  TABLE		*table;
34
  SQL_SELECT	*select=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35
  READ_RECORD	info;
36 37
  bool          using_limit=limit != HA_POS_ERROR;
  bool		transactional_table, safe_update, const_cond;
38
  bool          const_cond_result;
39
  ha_rows	deleted= 0;
40
  uint usable_index= MAX_KEY;
41
  SELECT_LEX   *select_lex= &thd->lex->select_lex;
42
  THD::killed_state killed_status= THD::NOT_KILLED;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
43 44
  DBUG_ENTER("mysql_delete");

45 46
  if (open_and_lock_tables(thd, table_list))
    DBUG_RETURN(TRUE);
47 48 49 50
  if (!(table= table_list->table))
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
	     table_list->view_db.str, table_list->view_name.str);
monty@mysql.com's avatar
monty@mysql.com committed
51
    DBUG_RETURN(TRUE);
52
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
53 54
  thd->proc_info="init";
  table->map=1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
55

56 57
  if (mysql_prepare_delete(thd, table_list, &conds))
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
  /* 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);
    }
  }

80 81 82 83
  const_cond= (!conds || conds->const_item());
  safe_update=test(thd->options & OPTION_SAFE_UPDATES);
  if (safe_update && const_cond)
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
84 85
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
86
    DBUG_RETURN(TRUE);
87 88
  }

89
  select_lex->no_error= thd->lex->ignore;
90

91 92 93 94 95 96
  const_cond_result= const_cond && (!conds || conds->val_int());
  if (thd->is_error())
  {
    /* Error evaluating val_int(). */
    DBUG_RETURN(TRUE);
  }
97 98 99 100
  /*
    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.
101 102 103 104 105 106 107 108 109 110 111 112 113 114

    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.
115
  */
116
  if (!using_limit && const_cond_result &&
117
      !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
118
      (thd->lex->sql_command == SQLCOM_TRUNCATE ||
119 120
       (!thd->current_stmt_binlog_row_based &&
        !(table->triggers && table->triggers->has_delete_triggers()))))
121
  {
122
    /* Update the table->file->stats.records number */
123
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
124
    ha_rows const maybe_deleted= table->file->stats.records;
125
    DBUG_PRINT("debug", ("Trying to use delete_all_rows()"));
126 127 128
    if (!(error=table->file->delete_all_rows()))
    {
      error= -1;				// ok
129
      deleted= maybe_deleted;
130 131 132 133 134 135 136 137 138 139
      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 */
  }
140 141 142 143 144 145 146
  if (conds)
  {
    Item::cond_result result;
    conds= remove_eq_conds(thd, conds, &result);
    if (result == Item::COND_FALSE)             // Impossible where
      limit= 0;
  }
147

148 149 150 151 152
#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (prune_partitions(thd, table, conds))
  {
    free_underlaid_joins(thd, select_lex);
    thd->row_count_func= 0;
153
    send_ok(thd, (ha_rows) thd->row_count_func);  // No matching records
154 155 156
    DBUG_RETURN(0);
  }
#endif
157
  /* Update the table->file->stats.records number */
158
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
159

160
  table->covering_keys.clear_all();
161
  table->quick_keys.clear_all();		// Can't use 'only index'
monty@mysql.com's avatar
monty@mysql.com committed
162
  select=make_select(table, 0, 0, conds, 0, &error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
163
  if (error)
164
    DBUG_RETURN(TRUE);
165
  if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
166 167
  {
    delete select;
168
    free_underlaid_joins(thd, select_lex);
169
    thd->row_count_func= 0;
170
    send_ok(thd, (ha_rows) thd->row_count_func);
171 172 173 174 175
    /*
      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.
    */
monty@tik.mysql.fi's avatar
monty@tik.mysql.fi committed
176
    DBUG_RETURN(0);				// Nothing to delete
bk@work.mysql.com's avatar
bk@work.mysql.com committed
177 178 179
  }

  /* If running in safe sql mode, don't allow updates without keys */
180
  if (table->quick_keys.is_clear_all())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
181
  {
182
    thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
183
    if (safe_update && !using_limit)
184 185
    {
      delete select;
186
      free_underlaid_joins(thd, select_lex);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
187 188
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
189
      DBUG_RETURN(TRUE);
190
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
191
  }
192
  if (options & OPTION_QUICK)
193 194
    (void) table->file->extra(HA_EXTRA_QUICK);

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

sergefp@mysql.com's avatar
sergefp@mysql.com committed
230 231 232 233
  /* If quick select is used, initialize it before retrieving rows. */
  if (select && select->quick && select->quick->reset())
  {
    delete select;
234
    free_underlaid_joins(thd, select_lex);
235
    DBUG_RETURN(TRUE);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
236
  }
237 238 239 240 241
  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);

242
  init_ftfuncs(thd, select_lex, 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
243
  thd->proc_info="updating";
244 245 246
  if (table->triggers && 
      table->triggers->has_triggers(TRG_EVENT_DELETE,
                                    TRG_ACTION_AFTER))
247
  {
248 249 250 251 252 253 254
    /*
      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;
255
  }
256 257
  else
    will_batch= !table->file->start_bulk_delete();
258 259


260 261
  table->mark_columns_needed_for_delete();

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
262
  while (!(error=info.read_record(&info)) && !thd->killed &&
263
	 ! thd->is_error())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
264
  {
265 266
    // thd->is_error() is tested to disallow delete row on error
    if (!(select && select->skip_record())&& ! thd->is_error() )
bk@work.mysql.com's avatar
bk@work.mysql.com committed
267
    {
268

269 270 271 272 273 274 275
      if (table->triggers &&
          table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                            TRG_ACTION_BEFORE, FALSE))
      {
        error= 1;
        break;
      }
276

277
      if (!(error= table->file->ha_delete_row(table->record[0])))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
278 279
      {
	deleted++;
280 281 282 283 284 285 286
        if (table->triggers &&
            table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                              TRG_ACTION_AFTER, FALSE))
        {
          error= 1;
          break;
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
287 288 289 290 291 292 293 294 295
	if (!--limit && using_limit)
	{
	  error= -1;
	  break;
	}
      }
      else
      {
	table->file->print_error(error,MYF(0));
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
296 297 298 299 300 301 302 303 304
	/*
	  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;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
305 306 307
	break;
      }
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
308 309
    else
      table->file->unlock_row();  // Row failed selection, release lock on it
bk@work.mysql.com's avatar
bk@work.mysql.com committed
310
  }
311
  killed_status= thd->killed;
312
  if (killed_status == THD::NOT_KILLED || thd->is_error())
313
    error= 1;					// Aborted
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
314 315 316 317 318 319
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
  {
    if (error != 1)
      table->file->print_error(loc_error,MYF(0));
    error=1;
  }
mronstrom@mysql.com's avatar
mronstrom@mysql.com committed
320
  thd->proc_info= "end";
bk@work.mysql.com's avatar
bk@work.mysql.com committed
321
  end_read_record(&info);
322
  if (options & OPTION_QUICK)
323
    (void) table->file->extra(HA_EXTRA_NORMAL);
324

osku@127.(none)'s avatar
osku@127.(none) committed
325
  if (reset_auto_increment && (error < 0))
326 327 328 329 330
  {
    /*
      We're really doing a truncate and need to reset the table's
      auto-increment counter.
    */
osku@127.(none)'s avatar
osku@127.(none) committed
331
    int error2= table->file->reset_auto_increment(0);
332 333 334 335

    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
    {
      table->file->print_error(error2, MYF(0));
osku@127.(none)'s avatar
osku@127.(none) committed
336
      error= 1;
337 338 339
    }
  }

340
cleanup:
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
341 342 343 344 345 346 347 348 349
  /*
    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);
  }

350
  delete select;
351
  transactional_table= table->file->has_transactions();
352

353 354 355
  if (!transactional_table && deleted > 0)
    thd->transaction.stmt.modified_non_trans_table= TRUE;
  
356
  /* See similar binlogging code in sql_update.cc, for comments */
357
  if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
358
  {
359 360
    if (mysql_bin_log.is_open())
    {
361
      if (error < 0)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
362
        thd->clear_error();
363
      /*
364 365 366 367
        [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.
368
      */
369
      int log_result= thd->binlog_query(THD::ROW_QUERY_TYPE,
370
                                        thd->query, thd->query_length,
371
                                        transactional_table, FALSE, killed_status);
372 373 374

      if (log_result && transactional_table)
      {
375
	error=1;
376
      }
377
    }
378 379
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
380
  }
381
  DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
382
  free_underlaid_joins(thd, select_lex);
383 384 385 386 387
  if (transactional_table)
  {
    if (ha_autocommit_or_rollback(thd,error >= 0))
      error=1;
  }
388

bk@work.mysql.com's avatar
bk@work.mysql.com committed
389 390 391 392 393
  if (thd->lock)
  {
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
  }
394
  if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
395
  {
396
    thd->row_count_func= deleted;
397
    send_ok(thd, (ha_rows) thd->row_count_func);
398
    DBUG_PRINT("info",("%ld records deleted",(long) deleted));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
399
  }
400
  DBUG_RETURN(error >= 0 || thd->is_error());
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
401 402 403 404 405 406 407 408 409
}


/*
  Prepare items in DELETE statement

  SYNOPSIS
    mysql_prepare_delete()
    thd			- thread handler
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
410
    table_list		- global/local table list
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
411 412 413
    conds		- conditions

  RETURN VALUE
414 415
    FALSE OK
    TRUE  error
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
416
*/
417
bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
418
{
419
  Item *fake_conds= 0;
420
  SELECT_LEX *select_lex= &thd->lex->select_lex;
421
  DBUG_ENTER("mysql_prepare_delete");
422
  List<Item> all_fields;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
423

igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
424
  thd->lex->allow_sum_func= 0;
425 426
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
427
                                    table_list, 
428
                                    &select_lex->leaf_tables, FALSE, 
429
                                    DELETE_ACL, SELECT_ACL) ||
430
      setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
431
      setup_ftfuncs(select_lex))
432
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
433
  if (!table_list->updatable || check_key_in_view(thd, table_list))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
434
  {
435
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
436
    DBUG_RETURN(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
437
  }
438
  {
439
    TABLE_LIST *duplicate;
440
    if ((duplicate= unique_table(thd, table_list, table_list->next_global, 0)))
441
    {
442
      update_non_unique_table_error(table_list, "DELETE", duplicate);
443 444
      DBUG_RETURN(TRUE);
    }
445
  }
446 447 448 449 450

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

451
  select_lex->fix_prepare_information(thd, conds, &fake_conds);
452
  DBUG_RETURN(FALSE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
453 454 455
}


456
/***************************************************************************
457
  Delete multiple tables from join 
458 459
***************************************************************************/

460
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
461

462
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
463
{
464
  handler *file= (handler*)arg;
465
  return file->cmp_ref((const uchar*)a, (const uchar*)b);
466
}
467

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
468 469 470 471 472 473 474 475
/*
  make delete specific preparation and checks after opening tables

  SYNOPSIS
    mysql_multi_delete_prepare()
    thd         thread handler

  RETURN
476 477
    FALSE OK
    TRUE  Error
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
478 479
*/

480
bool mysql_multi_delete_prepare(THD *thd)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
481 482
{
  LEX *lex= thd->lex;
483
  TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
484 485 486 487 488 489 490 491 492
  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
  */
493 494
  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
                                    &thd->lex->select_lex.top_join_list,
495
                                    lex->query_tables,
496
                                    &lex->select_lex.leaf_tables, FALSE, 
497
                                    DELETE_ACL, SELECT_ACL))
498
    DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
499

500 501 502 503 504 505

  /*
    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;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
506 507 508 509 510
  /* 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)
  {
511 512 513
    if (!(target_tbl->table= target_tbl->correspondent_table->table))
    {
      DBUG_ASSERT(target_tbl->correspondent_table->view &&
514 515 516
                  target_tbl->correspondent_table->merge_underlying_list &&
                  target_tbl->correspondent_table->merge_underlying_list->
                  next_local);
517 518 519 520 521 522
      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);
    }

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
523 524 525
    if (!target_tbl->correspondent_table->updatable ||
        check_key_in_view(thd, target_tbl->correspondent_table))
    {
526
      my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
527
               target_tbl->table_name, "DELETE");
528
      DBUG_RETURN(TRUE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
529 530
    }
    /*
531 532
      Check that table from which we delete is not used somewhere
      inside subqueries/view.
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
533 534
    */
    {
535
      TABLE_LIST *duplicate;
536
      if ((duplicate= unique_table(thd, target_tbl->correspondent_table,
537
                                   lex->query_tables, 0)))
538 539 540 541 542
      {
        update_non_unique_table_error(target_tbl->correspondent_table,
                                      "DELETE", duplicate);
        DBUG_RETURN(TRUE);
      }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
543 544
    }
  }
545
  DBUG_RETURN(FALSE);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
546 547 548
}


549 550
multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
  : delete_tables(dt), deleted(0), found(0),
551
    num_of_tables(num_of_tables_arg), error(0),
552
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
553
{
554
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
555 556 557 558
}


int
559
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
560 561
{
  DBUG_ENTER("multi_delete::prepare");
562
  unit= u;
563
  do_delete= 1;
564
  thd->proc_info="deleting from main table";
565 566 567
  DBUG_RETURN(0);
}

568

569
bool
570 571
multi_delete::initialize_tables(JOIN *join)
{
572
  TABLE_LIST *walk;
573 574 575 576 577 578
  Unique **tempfiles_ptr;
  DBUG_ENTER("initialize_tables");

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

579
  table_map tables_to_delete_from=0;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
580
  for (walk= delete_tables; walk; walk= walk->next_local)
581
    tables_to_delete_from|= walk->table->map;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
582

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

647

648 649
multi_delete::~multi_delete()
{
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
650 651 652
  for (table_being_deleted= delete_tables;
       table_being_deleted;
       table_being_deleted= table_being_deleted->next_local)
653
  {
654 655
    TABLE *table= table_being_deleted->table;
    table->no_keyread=0;
656
  }
657

658
  for (uint counter= 0; counter < num_of_tables; counter++)
659
  {
660
    if (tempfiles[counter])
661 662
      delete tempfiles[counter];
  }
663 664
}

665

666 667
bool multi_delete::send_data(List<Item> &values)
{
668 669
  int secure_counter= delete_while_scanning ? -1 : 0;
  TABLE_LIST *del_table;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
670 671
  DBUG_ENTER("multi_delete::send_data");

672 673 674
  for (del_table= delete_tables;
       del_table;
       del_table= del_table->next_local, secure_counter++)
675
  {
676
    TABLE *table= del_table->table;
677 678 679 680 681 682

    /* 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]);
683
    found++;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
684

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

723

724 725
void multi_delete::send_error(uint errcode,const char *err)
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
726 727
  DBUG_ENTER("multi_delete::send_error");

728
  /* First send error what ever it is ... */
729
  my_message(errcode, err, MYF(0));
730

731 732 733
  /* the error was handled or nothing deleted and no side effects return */
  if (error_handled ||
      !thd->transaction.stmt.modified_non_trans_table && !deleted)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
734
    DBUG_VOID_RETURN;
735

736
  /* Something already deleted so we have to invalidate cache */
737 738
  if (deleted)
    query_cache_invalidate3(thd, delete_tables, 1);
739

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

780

781

782 783 784 785 786 787 788
/*
  Do delete from other tables.
  Returns values:
	0 ok
	1 error
*/

789
int multi_delete::do_deletes()
790
{
791
  int local_error= 0, counter= 0, tmp_error;
mronstrom@mysql.com[mikron]'s avatar
mronstrom@mysql.com[mikron] committed
792
  bool will_batch;
793
  DBUG_ENTER("do_deletes");
794
  DBUG_ASSERT(do_delete);
795

796
  do_delete= 0;                                 // Mark called
797
  if (!found)
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
798
    DBUG_RETURN(0);
799 800 801 802 803

  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
                        delete_tables);
 
  for (; table_being_deleted;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
804
       table_being_deleted= table_being_deleted->next_local, counter++)
805
  { 
806
    ha_rows last_deleted= deleted;
807 808 809
    TABLE *table = table_being_deleted->table;
    if (tempfiles[counter]->get(table))
    {
810
      local_error=1;
811 812 813 814
      break;
    }

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

864

865
/*
866 867
  Send ok to the client

868 869 870 871
  return:  0 sucess
	   1 error
*/

872 873
bool multi_delete::send_eof()
{
874
  THD::killed_state killed_status= THD::NOT_KILLED;
875
  thd->proc_info="deleting from reference tables";
876 877

  /* Does deletes for the last n - 1 tables, returns 0 if ok */
878
  int local_error= do_deletes();		// returns 0 if success
879

880 881
  /* compute a total error to know if something failed */
  local_error= local_error || error;
882
  killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed;
883
  /* reset used flags */
884
  thd->proc_info="end";
885

886 887 888 889
  /*
    We must invalidate the query cache before binlog writing and
    ha_autocommit_...
  */
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
890
  if (deleted)
monty@mysql.com's avatar
monty@mysql.com committed
891
  {
heikki@hundin.mysql.fi's avatar
heikki@hundin.mysql.fi committed
892
    query_cache_invalidate3(thd, delete_tables, 1);
monty@mysql.com's avatar
monty@mysql.com committed
893
  }
894 895
  DBUG_ASSERT(!normal_tables || !deleted ||
              thd->transaction.stmt.modified_non_trans_table);
896
  if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
897
  {
898 899
    if (mysql_bin_log.is_open())
    {
900
      if (local_error == 0)
guilhem@mysql.com's avatar
guilhem@mysql.com committed
901
        thd->clear_error();
902 903
      if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                            thd->query, thd->query_length,
904
                            transactional_tables, FALSE, killed_status) &&
905 906
          !normal_tables)
      {
907
	local_error=1;  // Log write failed: roll back the SQL statement
908
      }
909
    }
910 911
    if (thd->transaction.stmt.modified_non_trans_table)
      thd->transaction.all.modified_non_trans_table= TRUE;
912
  }
913 914
  if (local_error != 0)
    error_handled= TRUE; // to force early leave from ::send_error()
915

916
  /* Commit or rollback the current SQL statement */
917 918 919 920
  if (transactional_tables)
    if (ha_autocommit_or_rollback(thd,local_error > 0))
      local_error=1;

921
  if (!local_error)
922 923
  {
    thd->row_count_func= deleted;
924
    ::send_ok(thd, (ha_rows) thd->row_count_func);
925
  }
926 927
  return 0;
}
928 929 930


/***************************************************************************
931
  TRUNCATE TABLE
932 933 934 935 936 937 938 939 940 941 942
****************************************************************************/

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

946
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
947 948 949
{
  HA_CREATE_INFO create_info;
  char path[FN_REFLEN];
950
  TABLE *table;
951
  bool error;
952
  uint path_length;
953 954
  DBUG_ENTER("mysql_truncate");

955
  bzero((char*) &create_info,sizeof(create_info));
956
  /* If it is a temporary table, close and regenerate it */
957
  if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
958
  {
antony@ppcg5.local's avatar
antony@ppcg5.local committed
959
    handlerton *table_type= table->s->db_type();
960
    TABLE_SHARE *share= table->s;
961
    if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
962
      goto trunc_by_del;
963 964 965 966 967 968

    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);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
969
    // We don't need to call invalidate() because this table is not in cache
970 971 972
    if ((error= (int) !(open_temporary_table(thd, share->path.str,
                                             share->db.str,
					     share->table_name.str, 1))))
973
      (void) rm_temporary_table(table_type, path);
974 975
    free_table_share(share);
    my_free((char*) table,MYF(0));
976
    /*
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
977 978
      If we return here we will not have logged the truncation to the bin log
      and we will not send_ok() to the client.
979
    */
serg@serg.mylan's avatar
serg@serg.mylan committed
980
    goto end;
981 982
  }

983
  path_length= build_table_filename(path, sizeof(path), table_list->db,
984
                                    table_list->table_name, reg_ext, 0);
985 986 987

  if (!dont_send_ok)
  {
988
    enum legacy_db_type table_type;
989
    mysql_frm_type(thd, path, &table_type);
990
    if (table_type == DB_TYPE_UNKNOWN)
991
    {
992
      my_error(ER_NO_SUCH_TABLE, MYF(0),
993
               table_list->db, table_list->table_name);
994
      DBUG_RETURN(TRUE);
995
    }
996
    if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
997
                                      HTON_CAN_RECREATE))
998
      goto trunc_by_del;
999

1000
    if (lock_and_wait_for_table_name(thd, table_list))
1001
      DBUG_RETURN(TRUE);
1002 1003
  }

1004 1005 1006
  // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
  // crashes, replacement works.  *(path + path_length - reg_ext_length)=
  // '\0';
1007
  path[path_length - reg_ext_length] = 0;
mskold@mysql.com's avatar
mskold@mysql.com committed
1008
  VOID(pthread_mutex_lock(&LOCK_open));
1009 1010
  error= ha_create_table(thd, path, table_list->db, table_list->table_name,
                         &create_info, 1);
mskold@mysql.com's avatar
mskold@mysql.com committed
1011
  VOID(pthread_mutex_unlock(&LOCK_open));
1012
  query_cache_invalidate3(thd, table_list, 0);
1013

1014
end:
1015
  if (!dont_send_ok)
1016
  {
1017
    if (!error)
1018
    {
1019 1020 1021 1022 1023
      /*
        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);
1024
      send_ok(thd);		// This should return record count
1025
    }
1026
    VOID(pthread_mutex_lock(&LOCK_open));
1027
    unlock_table_name(thd, table_list);
1028
    VOID(pthread_mutex_unlock(&LOCK_open));
1029
  }
1030
  else if (error)
1031 1032
  {
    VOID(pthread_mutex_lock(&LOCK_open));
1033
    unlock_table_name(thd, table_list);
1034 1035
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
1036
  DBUG_RETURN(error);
1037

1038
trunc_by_del:
1039
  /* Probably InnoDB table */
1040
  ulonglong save_options= thd->options;
1041 1042 1043
  table_list->lock_type= TL_WRITE;
  thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
  ha_enable_transaction(thd, FALSE);
1044
  mysql_init_select(thd->lex);
1045
  bool save_binlog_row_based= thd->current_stmt_binlog_row_based;
1046
  thd->clear_current_stmt_binlog_row_based();
1047
  error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
1048
                      HA_POS_ERROR, LL(0), TRUE);
1049 1050
  ha_enable_transaction(thd, TRUE);
  thd->options= save_options;
1051
  thd->current_stmt_binlog_row_based= save_binlog_row_based;
1052
  DBUG_RETURN(error);
1053
}