~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: devananda
  • Date: 2009-07-01 17:38:47 UTC
  • mto: (1093.1.7 captain)
  • mto: This revision was merged to the branch mainline in revision 1095.
  • Revision ID: devananda.vdv@gmail.com-20090701173847-3n3mbtessg5ff35e
refactored function/benchmark into plugin/benchmark

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