~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Jay Pipes
  • Date: 2009-02-28 17:49:22 UTC
  • mto: (910.2.6 mordred-noatomics)
  • mto: This revision was merged to the branch mainline in revision 908.
  • Revision ID: jpipes@serialcoder-20090228174922-jczgt4d0662fqmnf
Merging in old r902 temporal changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/*
17
17
  Delete of records and truncate of tables.
18
18
 
19
19
  Multi-table deletes were introduced by Monty and Sinisa
20
20
*/
21
 
#include "config.h"
22
 
#include "drizzled/sql_select.h"
23
 
#include "drizzled/error.h"
24
 
#include "drizzled/probes.h"
25
 
#include "drizzled/sql_parse.h"
26
 
#include "drizzled/sql_base.h"
27
 
#include "drizzled/lock.h"
28
 
#include "drizzled/probes.h"
29
 
#include "drizzled/optimizer/range.h"
30
 
#include "drizzled/records.h"
31
 
#include "drizzled/internal/iocache.h"
32
 
#include "drizzled/transaction_services.h"
33
 
#include "drizzled/filesort.h"
34
 
 
35
 
namespace drizzled
36
 
{
 
21
#include <drizzled/server_includes.h>
 
22
#include <drizzled/sql_select.h>
 
23
#include <drizzled/error.h>
 
24
#include <drizzled/probes.h>
 
25
#include <drizzled/sql_parse.h>
 
26
#include <drizzled/sql_base.h>
 
27
#include <drizzled/lock.h>
37
28
 
38
29
/**
39
30
  Implement DELETE SQL word.
44
35
*/
45
36
 
46
37
bool mysql_delete(Session *session, TableList *table_list, COND *conds,
47
 
                  SQL_LIST *order, ha_rows limit, uint64_t,
 
38
                  SQL_LIST *order, ha_rows limit, uint64_t options,
48
39
                  bool reset_auto_increment)
49
40
{
50
 
  int           error;
 
41
  bool          will_batch;
 
42
  int           error, loc_error;
51
43
  Table         *table;
52
 
  optimizer::SqlSelect *select= NULL;
53
 
  ReadRecord    info;
 
44
  SQL_SELECT    *select=0;
 
45
  READ_RECORD   info;
54
46
  bool          using_limit=limit != HA_POS_ERROR;
55
 
  bool          transactional_table, const_cond;
 
47
  bool          transactional_table, safe_update, const_cond;
56
48
  bool          const_cond_result;
57
49
  ha_rows       deleted= 0;
58
50
  uint32_t usable_index= MAX_KEY;
59
51
  Select_Lex   *select_lex= &session->lex->select_lex;
60
 
  Session::killed_state_t killed_status= Session::NOT_KILLED;
61
 
 
62
 
  if (session->openTablesLock(table_list))
63
 
  {
64
 
    DRIZZLE_DELETE_DONE(1, 0);
65
 
    return true;
66
 
  }
 
52
  Session::killed_state killed_status= Session::NOT_KILLED;
 
53
 
 
54
 
 
55
  if (open_and_lock_tables(session, table_list))
 
56
    return(true);
67
57
 
68
58
  table= table_list->table;
69
59
  assert(table);
72
62
  table->map=1;
73
63
 
74
64
  if (mysql_prepare_delete(session, table_list, &conds))
75
 
  {
76
 
    DRIZZLE_DELETE_DONE(1, 0);
77
 
    return true;
78
 
  }
 
65
    goto err;
79
66
 
80
67
  /* check ORDER BY even if it can be ignored */
81
68
  if (order && order->elements)
84
71
    List<Item>   fields;
85
72
    List<Item>   all_fields;
86
73
 
 
74
    memset(&tables, 0, sizeof(tables));
87
75
    tables.table = table;
88
76
    tables.alias = table_list->alias;
89
77
 
90
78
      if (select_lex->setup_ref_array(session, order->elements) ||
91
79
          setup_order(session, select_lex->ref_pointer_array, &tables,
92
 
                    fields, all_fields, (Order*) order->first))
93
 
      {
94
 
        delete select;
95
 
        free_underlaid_joins(session, &session->lex->select_lex);
96
 
        DRIZZLE_DELETE_DONE(1, 0);
97
 
 
98
 
        return true;
99
 
      }
 
80
                    fields, all_fields, (order_st*) order->first))
 
81
    {
 
82
      delete select;
 
83
      free_underlaid_joins(session, &session->lex->select_lex);
 
84
      goto err;
 
85
    }
100
86
  }
101
87
 
102
88
  const_cond= (!conds || conds->const_item());
 
89
  safe_update=test(session->options & OPTION_SAFE_UPDATES);
 
90
  if (safe_update && const_cond)
 
91
  {
 
92
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
93
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
94
    goto err;
 
95
  }
103
96
 
104
97
  select_lex->no_error= session->lex->ignore;
105
98
 
131
124
  */
132
125
  if (!using_limit && const_cond_result)
133
126
  {
134
 
    /* Update the table->cursor->stats.records number */
135
 
    table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
136
 
    ha_rows const maybe_deleted= table->cursor->stats.records;
137
 
    if (!(error=table->cursor->ha_delete_all_rows()))
 
127
    /* Update the table->file->stats.records number */
 
128
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
129
    ha_rows const maybe_deleted= table->file->stats.records;
 
130
    if (!(error=table->file->ha_delete_all_rows()))
138
131
    {
139
132
      error= -1;                                // ok
140
133
      deleted= maybe_deleted;
142
135
    }
143
136
    if (error != HA_ERR_WRONG_COMMAND)
144
137
    {
145
 
      table->print_error(error,MYF(0));
 
138
      table->file->print_error(error,MYF(0));
146
139
      error=0;
147
140
      goto cleanup;
148
141
    }
156
149
      limit= 0;
157
150
  }
158
151
 
159
 
  /* Update the table->cursor->stats.records number */
160
 
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
152
  /* Update the table->file->stats.records number */
 
153
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
161
154
 
162
 
  table->covering_keys.reset();
163
 
  table->quick_keys.reset();            // Can't use 'only index'
164
 
  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
 
155
  table->covering_keys.clear_all();
 
156
  table->quick_keys.clear_all();                // Can't use 'only index'
 
157
  select=make_select(table, 0, 0, conds, 0, &error);
165
158
  if (error)
166
 
  {
167
 
    DRIZZLE_DELETE_DONE(1, 0);
168
 
    return true;
169
 
  }
170
 
 
171
 
  if ((select && select->check_quick(session, false, limit)) || !limit)
 
159
    goto err;
 
160
  if ((select && select->check_quick(session, safe_update, limit)) || !limit)
172
161
  {
173
162
    delete select;
174
163
    free_underlaid_joins(session, select_lex);
175
164
    session->row_count_func= 0;
176
 
    DRIZZLE_DELETE_DONE(0, 0);
177
 
    /**
178
 
     * Resetting the Diagnostic area to prevent
179
 
     * lp bug# 439719
180
 
     */
181
 
    session->main_da.reset_diagnostics_area();
 
165
    DRIZZLE_DELETE_END();
182
166
    session->my_ok((ha_rows) session->row_count_func);
183
167
    /*
184
168
      We don't need to call reset_auto_increment in this case, because
185
169
      mysql_truncate always gives a NULL conds argument, hence we never
186
170
      get here.
187
171
    */
188
 
    return 0; // Nothing to delete
 
172
    return(0);                          // Nothing to delete
189
173
  }
190
174
 
191
175
  /* If running in safe sql mode, don't allow updates without keys */
192
 
  if (table->quick_keys.none())
 
176
  if (table->quick_keys.is_clear_all())
193
177
  {
194
178
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
179
    if (safe_update && !using_limit)
 
180
    {
 
181
      delete select;
 
182
      free_underlaid_joins(session, select_lex);
 
183
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
184
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
185
      goto err;
 
186
    }
195
187
  }
 
188
  if (options & OPTION_QUICK)
 
189
    (void) table->file->extra(HA_EXTRA_QUICK);
196
190
 
197
191
  if (order && order->elements)
198
192
  {
199
193
    uint32_t         length= 0;
200
 
    SortField  *sortorder;
 
194
    SORT_FIELD  *sortorder;
201
195
    ha_rows examined_rows;
202
196
 
203
 
    if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
204
 
      usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
 
197
    if ((!select || table->quick_keys.is_clear_all()) && limit != HA_POS_ERROR)
 
198
      usable_index= get_index_for_order(table, (order_st*)(order->first), limit);
205
199
 
206
200
    if (usable_index == MAX_KEY)
207
201
    {
208
 
      FileSort filesort(*session);
209
 
      table->sort.io_cache= new internal::IO_CACHE;
210
 
 
211
 
 
212
 
      if (not (sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL)) ||
213
 
          (table->sort.found_records = filesort.run(table, sortorder, length,
214
 
                                                    select, HA_POS_ERROR, 1,
215
 
                                                    examined_rows)) == HA_POS_ERROR)
 
202
      table->sort.io_cache= new IO_CACHE;
 
203
      memset(table->sort.io_cache, 0, sizeof(IO_CACHE));
 
204
 
 
205
 
 
206
      if (!(sortorder= make_unireg_sortorder((order_st*) order->first,
 
207
                                             &length, NULL)) ||
 
208
          (table->sort.found_records = filesort(session, table, sortorder, length,
 
209
                                                select, HA_POS_ERROR, 1,
 
210
                                                &examined_rows))
 
211
          == HA_POS_ERROR)
216
212
      {
217
213
        delete select;
218
214
        free_underlaid_joins(session, &session->lex->select_lex);
219
 
 
220
 
        DRIZZLE_DELETE_DONE(1, 0);
221
 
        return true;
 
215
        goto err;
222
216
      }
223
217
      /*
224
218
        Filesort has already found and selected the rows we want to delete,
235
229
  {
236
230
    delete select;
237
231
    free_underlaid_joins(session, select_lex);
238
 
    DRIZZLE_DELETE_DONE(1, 0);
239
 
    return true;
 
232
    goto err;
240
233
  }
241
 
 
242
234
  if (usable_index==MAX_KEY)
243
 
  {
244
 
    info.init_read_record(session,table,select,1,1);
245
 
  }
 
235
    init_read_record(&info,session,table,select,1,1);
246
236
  else
247
 
  {
248
 
    info.init_read_record_idx(session, table, 1, usable_index);
249
 
  }
 
237
    init_read_record_idx(&info, session, table, 1, usable_index);
250
238
 
251
239
  session->set_proc_info("updating");
252
240
 
 
241
  will_batch= !table->file->start_bulk_delete();
 
242
 
 
243
 
253
244
  table->mark_columns_needed_for_delete();
254
245
 
255
 
  while (!(error=info.read_record(&info)) && !session->getKilled() &&
 
246
  while (!(error=info.read_record(&info)) && !session->killed &&
256
247
         ! session->is_error())
257
248
  {
258
249
    // session->is_error() is tested to disallow delete row on error
259
250
    if (!(select && select->skip_record())&& ! session->is_error() )
260
251
    {
261
 
      if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
 
252
      if (!(error= table->file->ha_delete_row(table->record[0])))
262
253
      {
263
254
        deleted++;
264
255
        if (!--limit && using_limit)
269
260
      }
270
261
      else
271
262
      {
272
 
        table->print_error(error,MYF(0));
 
263
        table->file->print_error(error,MYF(0));
273
264
        /*
274
265
          In < 4.0.14 we set the error number to 0 here, but that
275
266
          was not sensible, because then MySQL would not roll back the
283
274
      }
284
275
    }
285
276
    else
286
 
      table->cursor->unlock_row();  // Row failed selection, release lock on it
 
277
      table->file->unlock_row();  // Row failed selection, release lock on it
287
278
  }
288
 
  killed_status= session->getKilled();
 
279
  killed_status= session->killed;
289
280
  if (killed_status != Session::NOT_KILLED || session->is_error())
290
281
    error= 1;                                   // Aborted
291
 
 
 
282
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
 
283
  {
 
284
    if (error != 1)
 
285
      table->file->print_error(loc_error,MYF(0));
 
286
    error=1;
 
287
  }
292
288
  session->set_proc_info("end");
293
 
  info.end_read_record();
294
 
 
295
 
cleanup:
 
289
  end_read_record(&info);
 
290
  if (options & OPTION_QUICK)
 
291
    (void) table->file->extra(HA_EXTRA_NORMAL);
296
292
 
297
293
  if (reset_auto_increment && (error < 0))
298
294
  {
300
296
      We're really doing a truncate and need to reset the table's
301
297
      auto-increment counter.
302
298
    */
303
 
    int error2= table->cursor->ha_reset_auto_increment(0);
 
299
    int error2= table->file->ha_reset_auto_increment(0);
304
300
 
305
301
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
306
302
    {
307
 
      table->print_error(error2, MYF(0));
 
303
      table->file->print_error(error2, MYF(0));
308
304
      error= 1;
309
305
    }
310
306
  }
311
307
 
 
308
cleanup:
 
309
 
312
310
  delete select;
313
 
  transactional_table= table->cursor->has_transactions();
 
311
  transactional_table= table->file->has_transactions();
314
312
 
315
313
  if (!transactional_table && deleted > 0)
316
 
    session->transaction.stmt.markModifiedNonTransData();
 
314
    session->transaction.stmt.modified_non_trans_table= true;
317
315
 
318
316
  /* See similar binlogging code in sql_update.cc, for comments */
319
 
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
 
317
  if ((error < 0) || session->transaction.stmt.modified_non_trans_table)
320
318
  {
321
 
    if (session->transaction.stmt.hasModifiedNonTransData())
322
 
      session->transaction.all.markModifiedNonTransData();
 
319
    if (session->transaction.stmt.modified_non_trans_table)
 
320
      session->transaction.all.modified_non_trans_table= true;
323
321
  }
324
 
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
 
322
  assert(transactional_table || !deleted || session->transaction.stmt.modified_non_trans_table);
325
323
  free_underlaid_joins(session, select_lex);
326
324
 
327
 
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
 
325
  DRIZZLE_DELETE_END();
328
326
  if (error < 0 || (session->lex->ignore && !session->is_fatal_error))
329
327
  {
330
328
    session->row_count_func= deleted;
331
 
    /**
332
 
     * Resetting the Diagnostic area to prevent
333
 
     * lp bug# 439719
334
 
     */
335
 
    session->main_da.reset_diagnostics_area();    
336
329
    session->my_ok((ha_rows) session->row_count_func);
337
330
  }
338
 
  session->status_var.deleted_row_count+= deleted;
 
331
  return(error >= 0 || session->is_error());
339
332
 
340
 
  return (error >= 0 || session->is_error());
 
333
err:
 
334
  DRIZZLE_DELETE_END();
 
335
  return(true);
341
336
}
342
337
 
343
338
 
365
360
                                    &session->lex->select_lex.top_join_list,
366
361
                                    table_list,
367
362
                                    &select_lex->leaf_tables, false) ||
368
 
      session->setup_conds(table_list, conds))
 
363
      setup_conds(session, table_list, select_lex->leaf_tables, conds))
369
364
    return(true);
370
365
  {
371
366
    TableList *duplicate;
372
 
    if ((duplicate= unique_table(table_list, table_list->next_global)))
 
367
    if ((duplicate= unique_table(session, table_list, table_list->next_global, 0)))
373
368
    {
374
 
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
 
369
      update_non_unique_table_error(table_list, "DELETE", duplicate);
375
370
      return(true);
376
371
    }
377
372
  }
385
380
 
386
381
 
387
382
/***************************************************************************
 
383
  Delete multiple tables from join
 
384
***************************************************************************/
 
385
 
 
386
#define MEM_STRIP_BUF_SIZE current_session->variables.sortbuff_size
 
387
 
 
388
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
 
389
{
 
390
  handler *file= (handler*)arg;
 
391
  return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
 
392
}
 
393
 
 
394
/*
 
395
  make delete specific preparation and checks after opening tables
 
396
 
 
397
  SYNOPSIS
 
398
    mysql_multi_delete_prepare()
 
399
    session         thread handler
 
400
 
 
401
  RETURN
 
402
    false OK
 
403
    true  Error
 
404
*/
 
405
 
 
406
int mysql_multi_delete_prepare(Session *session)
 
407
{
 
408
  LEX *lex= session->lex;
 
409
  TableList *aux_tables= (TableList *)lex->auxiliary_table_list.first;
 
410
  TableList *target_tbl;
 
411
 
 
412
 
 
413
  /*
 
414
    setup_tables() need for VIEWs. JOIN::prepare() will not do it second
 
415
    time.
 
416
 
 
417
    lex->query_tables also point on local list of DELETE Select_Lex
 
418
  */
 
419
  if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
 
420
                                    &session->lex->select_lex.top_join_list,
 
421
                                    lex->query_tables,
 
422
                                    &lex->select_lex.leaf_tables, false))
 
423
    return(true);
 
424
 
 
425
 
 
426
  /*
 
427
    Multi-delete can't be constructed over-union => we always have
 
428
    single SELECT on top and have to check underlying SELECTs of it
 
429
  */
 
430
  lex->select_lex.exclude_from_table_unique_test= true;
 
431
  /* Fix tables-to-be-deleted-from list to point at opened tables */
 
432
  for (target_tbl= (TableList*) aux_tables;
 
433
       target_tbl;
 
434
       target_tbl= target_tbl->next_local)
 
435
  {
 
436
    target_tbl->table= target_tbl->correspondent_table->table;
 
437
    assert(target_tbl->table);
 
438
 
 
439
    /*
 
440
      Check that table from which we delete is not used somewhere
 
441
      inside subqueries/view.
 
442
    */
 
443
    {
 
444
      TableList *duplicate;
 
445
      if ((duplicate= unique_table(session, target_tbl->correspondent_table,
 
446
                                   lex->query_tables, 0)))
 
447
      {
 
448
        update_non_unique_table_error(target_tbl->correspondent_table,
 
449
                                      "DELETE", duplicate);
 
450
        return(true);
 
451
      }
 
452
    }
 
453
  }
 
454
  return(false);
 
455
}
 
456
 
 
457
 
 
458
multi_delete::multi_delete(TableList *dt, uint32_t num_of_tables_arg)
 
459
  : delete_tables(dt), deleted(0), found(0),
 
460
    num_of_tables(num_of_tables_arg), error(0),
 
461
    do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0)
 
462
{
 
463
  tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
 
464
}
 
465
 
 
466
 
 
467
int
 
468
multi_delete::prepare(List<Item> &, Select_Lex_Unit *u)
 
469
{
 
470
 
 
471
  unit= u;
 
472
  do_delete= 1;
 
473
  session->set_proc_info("deleting from main table");
 
474
  return(0);
 
475
}
 
476
 
 
477
 
 
478
bool
 
479
multi_delete::initialize_tables(JOIN *join)
 
480
{
 
481
  TableList *walk;
 
482
  Unique **tempfiles_ptr;
 
483
 
 
484
 
 
485
  if ((session->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
 
486
    return(1);
 
487
 
 
488
  table_map tables_to_delete_from=0;
 
489
  for (walk= delete_tables; walk; walk= walk->next_local)
 
490
    tables_to_delete_from|= walk->table->map;
 
491
 
 
492
  walk= delete_tables;
 
493
  delete_while_scanning= 1;
 
494
  for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
 
495
       tab < end;
 
496
       tab++)
 
497
  {
 
498
    if (tab->table->map & tables_to_delete_from)
 
499
    {
 
500
      /* We are going to delete from this table */
 
501
      Table *tbl=walk->table=tab->table;
 
502
      walk= walk->next_local;
 
503
      /* Don't use KEYREAD optimization on this table */
 
504
      tbl->no_keyread=1;
 
505
      /* Don't use record cache */
 
506
      tbl->no_cache= 1;
 
507
      tbl->covering_keys.clear_all();
 
508
      if (tbl->file->has_transactions())
 
509
        transactional_tables= 1;
 
510
      else
 
511
        normal_tables= 1;
 
512
      tbl->prepare_for_position();
 
513
      tbl->mark_columns_needed_for_delete();
 
514
    }
 
515
    else if ((tab->type != JT_SYSTEM && tab->type != JT_CONST) &&
 
516
             walk == delete_tables)
 
517
    {
 
518
      /*
 
519
        We are not deleting from the table we are scanning. In this
 
520
        case send_data() shouldn't delete any rows a we may touch
 
521
        the rows in the deleted table many times
 
522
      */
 
523
      delete_while_scanning= 0;
 
524
    }
 
525
  }
 
526
  walk= delete_tables;
 
527
  tempfiles_ptr= tempfiles;
 
528
  if (delete_while_scanning)
 
529
  {
 
530
    table_being_deleted= delete_tables;
 
531
    walk= walk->next_local;
 
532
  }
 
533
  for (;walk ;walk= walk->next_local)
 
534
  {
 
535
    Table *table=walk->table;
 
536
    *tempfiles_ptr++= new Unique (refpos_order_cmp,
 
537
                                  (void *) table->file,
 
538
                                  table->file->ref_length,
 
539
                                  MEM_STRIP_BUF_SIZE);
 
540
  }
 
541
  return(session->is_fatal_error != 0);
 
542
}
 
543
 
 
544
 
 
545
multi_delete::~multi_delete()
 
546
{
 
547
  for (table_being_deleted= delete_tables;
 
548
       table_being_deleted;
 
549
       table_being_deleted= table_being_deleted->next_local)
 
550
  {
 
551
    Table *table= table_being_deleted->table;
 
552
    table->no_keyread=0;
 
553
  }
 
554
 
 
555
  for (uint32_t counter= 0; counter < num_of_tables; counter++)
 
556
  {
 
557
    if (tempfiles[counter])
 
558
      delete tempfiles[counter];
 
559
  }
 
560
}
 
561
 
 
562
 
 
563
bool multi_delete::send_data(List<Item> &)
 
564
{
 
565
  int secure_counter= delete_while_scanning ? -1 : 0;
 
566
  TableList *del_table;
 
567
 
 
568
 
 
569
  for (del_table= delete_tables;
 
570
       del_table;
 
571
       del_table= del_table->next_local, secure_counter++)
 
572
  {
 
573
    Table *table= del_table->table;
 
574
 
 
575
    /* Check if we are using outer join and we didn't find the row */
 
576
    if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
 
577
      continue;
 
578
 
 
579
    table->file->position(table->record[0]);
 
580
    found++;
 
581
 
 
582
    if (secure_counter < 0)
 
583
    {
 
584
      /* We are scanning the current table */
 
585
      assert(del_table == table_being_deleted);
 
586
      table->status|= STATUS_DELETED;
 
587
      if (!(error=table->file->ha_delete_row(table->record[0])))
 
588
      {
 
589
        deleted++;
 
590
        if (!table->file->has_transactions())
 
591
          session->transaction.stmt.modified_non_trans_table= true;
 
592
      }
 
593
      else
 
594
      {
 
595
        table->file->print_error(error,MYF(0));
 
596
        return(1);
 
597
      }
 
598
    }
 
599
    else
 
600
    {
 
601
      error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
 
602
      if (error)
 
603
      {
 
604
        error= 1;                               // Fatal error
 
605
        return(1);
 
606
      }
 
607
    }
 
608
  }
 
609
  return(0);
 
610
}
 
611
 
 
612
 
 
613
void multi_delete::send_error(uint32_t errcode,const char *err)
 
614
{
 
615
 
 
616
 
 
617
  /* First send error what ever it is ... */
 
618
  my_message(errcode, err, MYF(0));
 
619
 
 
620
  return;
 
621
}
 
622
 
 
623
 
 
624
void multi_delete::abort()
 
625
{
 
626
 
 
627
 
 
628
  /* the error was handled or nothing deleted and no side effects return */
 
629
  if (error_handled ||
 
630
      (!session->transaction.stmt.modified_non_trans_table && !deleted))
 
631
    return;
 
632
 
 
633
  /*
 
634
    If rows from the first table only has been deleted and it is
 
635
    transactional, just do rollback.
 
636
    The same if all tables are transactional, regardless of where we are.
 
637
    In all other cases do attempt deletes ...
 
638
  */
 
639
  if (do_delete && normal_tables &&
 
640
      (table_being_deleted != delete_tables ||
 
641
       !table_being_deleted->table->file->has_transactions()))
 
642
  {
 
643
    /*
 
644
      We have to execute the recorded do_deletes() and write info into the
 
645
      error log
 
646
    */
 
647
    error= 1;
 
648
    send_eof();
 
649
    assert(error_handled);
 
650
    return;
 
651
  }
 
652
 
 
653
  if (session->transaction.stmt.modified_non_trans_table)
 
654
  {
 
655
    session->transaction.all.modified_non_trans_table= true;
 
656
  }
 
657
  return;
 
658
}
 
659
 
 
660
 
 
661
 
 
662
/*
 
663
  Do delete from other tables.
 
664
  Returns values:
 
665
        0 ok
 
666
        1 error
 
667
*/
 
668
 
 
669
int multi_delete::do_deletes()
 
670
{
 
671
  int local_error= 0, counter= 0, tmp_error;
 
672
  bool will_batch;
 
673
 
 
674
  assert(do_delete);
 
675
 
 
676
  do_delete= 0;                                 // Mark called
 
677
  if (!found)
 
678
    return(0);
 
679
 
 
680
  table_being_deleted= (delete_while_scanning ? delete_tables->next_local :
 
681
                        delete_tables);
 
682
 
 
683
  for (; table_being_deleted;
 
684
       table_being_deleted= table_being_deleted->next_local, counter++)
 
685
  {
 
686
    ha_rows last_deleted= deleted;
 
687
    Table *table = table_being_deleted->table;
 
688
    if (tempfiles[counter]->get(table))
 
689
    {
 
690
      local_error=1;
 
691
      break;
 
692
    }
 
693
 
 
694
    READ_RECORD info;
 
695
    init_read_record(&info,session,table,NULL,0,1);
 
696
    /*
 
697
      Ignore any rows not found in reference tables as they may already have
 
698
      been deleted by foreign key handling
 
699
    */
 
700
    info.ignore_not_found_rows= 1;
 
701
    will_batch= !table->file->start_bulk_delete();
 
702
    while (!(local_error=info.read_record(&info)) && !session->killed)
 
703
    {
 
704
      if ((local_error=table->file->ha_delete_row(table->record[0])))
 
705
      {
 
706
        table->file->print_error(local_error,MYF(0));
 
707
        break;
 
708
      }
 
709
      deleted++;
 
710
    }
 
711
    if (will_batch && (tmp_error= table->file->end_bulk_delete()))
 
712
    {
 
713
      if (!local_error)
 
714
      {
 
715
        local_error= tmp_error;
 
716
        table->file->print_error(local_error,MYF(0));
 
717
      }
 
718
    }
 
719
    if (last_deleted != deleted && !table->file->has_transactions())
 
720
      session->transaction.stmt.modified_non_trans_table= true;
 
721
    end_read_record(&info);
 
722
    if (session->killed && !local_error)
 
723
      local_error= 1;
 
724
    if (local_error == -1)                              // End of file
 
725
      local_error = 0;
 
726
  }
 
727
  return(local_error);
 
728
}
 
729
 
 
730
 
 
731
/*
 
732
  Send ok to the client
 
733
 
 
734
  return:  0 sucess
 
735
           1 error
 
736
*/
 
737
 
 
738
bool multi_delete::send_eof()
 
739
{
 
740
  Session::killed_state killed_status= Session::NOT_KILLED;
 
741
  session->set_proc_info("deleting from reference tables");
 
742
 
 
743
  /* Does deletes for the last n - 1 tables, returns 0 if ok */
 
744
  int local_error= do_deletes();                // returns 0 if success
 
745
 
 
746
  /* compute a total error to know if something failed */
 
747
  local_error= local_error || error;
 
748
  killed_status= (local_error == 0)? Session::NOT_KILLED : session->killed;
 
749
  /* reset used flags */
 
750
  session->set_proc_info("end");
 
751
 
 
752
  if ((local_error == 0) || session->transaction.stmt.modified_non_trans_table)
 
753
  {
 
754
    if (session->transaction.stmt.modified_non_trans_table)
 
755
      session->transaction.all.modified_non_trans_table= true;
 
756
  }
 
757
  if (local_error != 0)
 
758
    error_handled= true; // to force early leave from ::send_error()
 
759
 
 
760
  if (!local_error)
 
761
  {
 
762
    session->row_count_func= deleted;
 
763
    session->my_ok((ha_rows) session->row_count_func);
 
764
  }
 
765
  return 0;
 
766
}
 
767
 
 
768
 
 
769
/***************************************************************************
388
770
  TRUNCATE Table
389
771
****************************************************************************/
390
772
 
391
773
/*
392
774
  Optimize delete of all rows by doing a full generate of the table
393
775
  This will work even if the .ISM and .ISD tables are destroyed
 
776
 
 
777
  dont_send_ok should be set if:
 
778
  - We should always wants to generate the table (even if the table type
 
779
    normally can't safely do this.
 
780
  - We don't want an ok to be sent to the end user.
 
781
  - We don't want to log the truncate command
 
782
  - If we want to have a name lock on the table on exit without errors.
394
783
*/
395
784
 
396
 
bool mysql_truncate(Session& session, TableList *table_list)
 
785
bool mysql_truncate(Session *session, TableList *table_list, bool dont_send_ok)
397
786
{
 
787
  HA_CREATE_INFO create_info;
 
788
  char path[FN_REFLEN];
 
789
  Table *table;
398
790
  bool error;
399
 
  TransactionServices &transaction_services= TransactionServices::singleton();
400
 
 
401
 
  uint64_t save_options= session.options;
 
791
  uint32_t path_length;
 
792
 
 
793
 
 
794
  memset(&create_info, 0, sizeof(create_info));
 
795
  /* If it is a temporary table, close and regenerate it */
 
796
  if (!dont_send_ok && (table= find_temporary_table(session, table_list)))
 
797
  {
 
798
    handlerton *table_type= table->s->db_type();
 
799
    TABLE_SHARE *share= table->s;
 
800
 
 
801
    if (!ha_check_storage_engine_flag(table_type, HTON_BIT_CAN_RECREATE))
 
802
      goto trunc_by_del;
 
803
 
 
804
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
 
805
 
 
806
    close_temporary_table(session, table, 0, 0);    // Don't free share
 
807
    ha_create_table(session, share->normalized_path.str,
 
808
                    share->db.str, share->table_name.str, &create_info, 1);
 
809
    // We don't need to call invalidate() because this table is not in cache
 
810
    if ((error= (int) !(open_temporary_table(session, share->path.str,
 
811
                                             share->db.str,
 
812
                                             share->table_name.str, 1,
 
813
                                             OTM_OPEN))))
 
814
      (void) rm_temporary_table(table_type, path);
 
815
    free_table_share(share);
 
816
    free((char*) table);
 
817
    /*
 
818
      If we return here we will not have logged the truncation to the bin log
 
819
      and we will not my_ok() to the client.
 
820
    */
 
821
    goto end;
 
822
  }
 
823
 
 
824
  path_length= build_table_filename(path, sizeof(path), table_list->db,
 
825
                                    table_list->table_name, reg_ext, 0);
 
826
 
 
827
  if (!dont_send_ok)
 
828
    goto trunc_by_del;
 
829
 
 
830
  // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
 
831
  // crashes, replacement works.  *(path + path_length - reg_ext_length)=
 
832
  // '\0';
 
833
  path[path_length - reg_ext_length] = 0;
 
834
  pthread_mutex_lock(&LOCK_open);
 
835
  error= ha_create_table(session, path, table_list->db, table_list->table_name,
 
836
                         &create_info, 1);
 
837
  pthread_mutex_unlock(&LOCK_open);
 
838
 
 
839
end:
 
840
  if (!dont_send_ok)
 
841
  {
 
842
    if (!error)
 
843
    {
 
844
      /*
 
845
        TRUNCATE must always be statement-based binlogged (not row-based) so
 
846
        we don't test current_stmt_binlog_row_based.
 
847
      */
 
848
      write_bin_log(session, true, session->query, session->query_length);
 
849
      session->my_ok();         // This should return record count
 
850
    }
 
851
    pthread_mutex_lock(&LOCK_open);
 
852
    unlock_table_name(session, table_list);
 
853
    pthread_mutex_unlock(&LOCK_open);
 
854
  }
 
855
  else if (error)
 
856
  {
 
857
    pthread_mutex_lock(&LOCK_open);
 
858
    unlock_table_name(session, table_list);
 
859
    pthread_mutex_unlock(&LOCK_open);
 
860
  }
 
861
  return(error);
 
862
 
 
863
trunc_by_del:
 
864
  /* Probably InnoDB table */
 
865
  uint64_t save_options= session->options;
402
866
  table_list->lock_type= TL_WRITE;
403
 
  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
404
 
  mysql_init_select(session.lex);
405
 
  error= mysql_delete(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
 
867
  session->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
 
868
  ha_enable_transaction(session, false);
 
869
  mysql_init_select(session->lex);
 
870
  error= mysql_delete(session, table_list, (COND*) 0, (SQL_LIST*) 0,
406
871
                      HA_POS_ERROR, 0L, true);
 
872
  ha_enable_transaction(session, true);
407
873
  /*
408
874
    Safety, in case the engine ignored ha_enable_transaction(false)
409
875
    above. Also clears session->transaction.*.
410
876
  */
411
 
  error= transaction_services.autocommitOrRollback(&session, error);
412
 
  session.options= save_options;
413
 
 
414
 
  return error;
 
877
  error= ha_autocommit_or_rollback(session, error);
 
878
  ha_commit(session);
 
879
  session->options= save_options;
 
880
  return(error);
415
881
}
416
 
 
417
 
} /* namespace drizzled */