~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
34
 
namespace drizzled
35
 
{
 
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>
36
28
 
37
29
/**
38
30
  Implement DELETE SQL word.
43
35
*/
44
36
 
45
37
bool mysql_delete(Session *session, TableList *table_list, COND *conds,
46
 
                  SQL_LIST *order, ha_rows limit, uint64_t,
 
38
                  SQL_LIST *order, ha_rows limit, uint64_t options,
47
39
                  bool reset_auto_increment)
48
40
{
49
 
  int           error;
 
41
  bool          will_batch;
 
42
  int           error, loc_error;
50
43
  Table         *table;
51
 
  optimizer::SqlSelect *select= NULL;
 
44
  SQL_SELECT    *select=0;
52
45
  READ_RECORD   info;
53
46
  bool          using_limit=limit != HA_POS_ERROR;
54
 
  bool          transactional_table, const_cond;
 
47
  bool          transactional_table, safe_update, const_cond;
55
48
  bool          const_cond_result;
56
49
  ha_rows       deleted= 0;
57
50
  uint32_t usable_index= MAX_KEY;
58
51
  Select_Lex   *select_lex= &session->lex->select_lex;
59
52
  Session::killed_state killed_status= Session::NOT_KILLED;
60
53
 
 
54
 
61
55
  if (session->openTablesLock(table_list))
62
56
  {
63
57
    DRIZZLE_DELETE_DONE(1, 0);
95
89
  }
96
90
 
97
91
  const_cond= (!conds || conds->const_item());
 
92
  safe_update=test(session->options & OPTION_SAFE_UPDATES);
 
93
  if (safe_update && const_cond)
 
94
  {
 
95
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
96
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
97
    goto err;
 
98
  }
98
99
 
99
100
  select_lex->no_error= session->lex->ignore;
100
101
 
126
127
  */
127
128
  if (!using_limit && const_cond_result)
128
129
  {
129
 
    /* Update the table->cursor->stats.records number */
130
 
    table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
131
 
    ha_rows const maybe_deleted= table->cursor->stats.records;
132
 
    if (!(error=table->cursor->ha_delete_all_rows()))
 
130
    /* Update the table->file->stats.records number */
 
131
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
132
    ha_rows const maybe_deleted= table->file->stats.records;
 
133
    if (!(error=table->file->ha_delete_all_rows()))
133
134
    {
134
135
      error= -1;                                // ok
135
136
      deleted= maybe_deleted;
137
138
    }
138
139
    if (error != HA_ERR_WRONG_COMMAND)
139
140
    {
140
 
      table->print_error(error,MYF(0));
 
141
      table->file->print_error(error,MYF(0));
141
142
      error=0;
142
143
      goto cleanup;
143
144
    }
151
152
      limit= 0;
152
153
  }
153
154
 
154
 
  /* Update the table->cursor->stats.records number */
155
 
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
155
  /* Update the table->file->stats.records number */
 
156
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
156
157
 
157
158
  table->covering_keys.reset();
158
159
  table->quick_keys.reset();            // Can't use 'only index'
159
 
  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
 
160
  select=make_select(table, 0, 0, conds, 0, &error);
160
161
  if (error)
161
162
    goto err;
162
 
  if ((select && select->check_quick(session, false, limit)) || !limit)
 
163
  if ((select && select->check_quick(session, safe_update, limit)) || !limit)
163
164
  {
164
165
    delete select;
165
166
    free_underlaid_joins(session, select_lex);
166
167
    session->row_count_func= 0;
167
 
    DRIZZLE_DELETE_DONE(0, 0);
168
 
    /**
169
 
     * Resetting the Diagnostic area to prevent
170
 
     * lp bug# 439719
171
 
     */
172
 
    session->main_da.reset_diagnostics_area();
 
168
    DRIZZLE_DELETE_END(0, 0);
173
169
    session->my_ok((ha_rows) session->row_count_func);
174
170
    /*
175
171
      We don't need to call reset_auto_increment in this case, because
183
179
  if (table->quick_keys.none())
184
180
  {
185
181
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
182
    if (safe_update && !using_limit)
 
183
    {
 
184
      delete select;
 
185
      free_underlaid_joins(session, select_lex);
 
186
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
187
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
188
      goto err;
 
189
    }
186
190
  }
 
191
  if (options & OPTION_QUICK)
 
192
    (void) table->file->extra(HA_EXTRA_QUICK);
187
193
 
188
194
  if (order && order->elements)
189
195
  {
192
198
    ha_rows examined_rows;
193
199
 
194
200
    if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
195
 
      usable_index= optimizer::get_index_for_order(table, (order_st*)(order->first), limit);
 
201
      usable_index= get_index_for_order(table, (order_st*)(order->first), limit);
196
202
 
197
203
    if (usable_index == MAX_KEY)
198
204
    {
199
 
      table->sort.io_cache= new internal::IO_CACHE;
200
 
      memset(table->sort.io_cache, 0, sizeof(internal::IO_CACHE));
 
205
      table->sort.io_cache= new IO_CACHE;
 
206
      memset(table->sort.io_cache, 0, sizeof(IO_CACHE));
201
207
 
202
208
 
203
209
      if (!(sortorder= make_unireg_sortorder((order_st*) order->first,
228
234
    free_underlaid_joins(session, select_lex);
229
235
    goto err;
230
236
  }
231
 
 
232
237
  if (usable_index==MAX_KEY)
233
238
    init_read_record(&info,session,table,select,1,1);
234
239
  else
236
241
 
237
242
  session->set_proc_info("updating");
238
243
 
 
244
  will_batch= !table->file->start_bulk_delete();
 
245
 
 
246
 
239
247
  table->mark_columns_needed_for_delete();
240
248
 
241
249
  while (!(error=info.read_record(&info)) && !session->killed &&
244
252
    // session->is_error() is tested to disallow delete row on error
245
253
    if (!(select && select->skip_record())&& ! session->is_error() )
246
254
    {
247
 
      if (!(error= table->cursor->ha_delete_row(table->record[0])))
 
255
      if (!(error= table->file->ha_delete_row(table->record[0])))
248
256
      {
249
257
        deleted++;
250
258
        if (!--limit && using_limit)
255
263
      }
256
264
      else
257
265
      {
258
 
        table->print_error(error,MYF(0));
 
266
        table->file->print_error(error,MYF(0));
259
267
        /*
260
268
          In < 4.0.14 we set the error number to 0 here, but that
261
269
          was not sensible, because then MySQL would not roll back the
269
277
      }
270
278
    }
271
279
    else
272
 
      table->cursor->unlock_row();  // Row failed selection, release lock on it
 
280
      table->file->unlock_row();  // Row failed selection, release lock on it
273
281
  }
274
282
  killed_status= session->killed;
275
283
  if (killed_status != Session::NOT_KILLED || session->is_error())
276
284
    error= 1;                                   // Aborted
277
 
 
 
285
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
 
286
  {
 
287
    if (error != 1)
 
288
      table->file->print_error(loc_error,MYF(0));
 
289
    error=1;
 
290
  }
278
291
  session->set_proc_info("end");
279
292
  end_read_record(&info);
280
 
 
281
 
cleanup:
 
293
  if (options & OPTION_QUICK)
 
294
    (void) table->file->extra(HA_EXTRA_NORMAL);
282
295
 
283
296
  if (reset_auto_increment && (error < 0))
284
297
  {
286
299
      We're really doing a truncate and need to reset the table's
287
300
      auto-increment counter.
288
301
    */
289
 
    int error2= table->cursor->ha_reset_auto_increment(0);
 
302
    int error2= table->file->ha_reset_auto_increment(0);
290
303
 
291
304
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
292
305
    {
293
 
      table->print_error(error2, MYF(0));
 
306
      table->file->print_error(error2, MYF(0));
294
307
      error= 1;
295
308
    }
296
309
  }
297
310
 
 
311
cleanup:
 
312
 
298
313
  delete select;
299
 
  transactional_table= table->cursor->has_transactions();
 
314
  transactional_table= table->file->has_transactions();
300
315
 
301
316
  if (!transactional_table && deleted > 0)
302
 
    session->transaction.stmt.markModifiedNonTransData();
 
317
    session->transaction.stmt.modified_non_trans_table= true;
303
318
 
304
319
  /* See similar binlogging code in sql_update.cc, for comments */
305
 
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
 
320
  if ((error < 0) || session->transaction.stmt.modified_non_trans_table)
306
321
  {
307
 
    if (session->transaction.stmt.hasModifiedNonTransData())
308
 
      session->transaction.all.markModifiedNonTransData();
 
322
    if (session->transaction.stmt.modified_non_trans_table)
 
323
      session->transaction.all.modified_non_trans_table= true;
309
324
  }
310
 
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
 
325
  assert(transactional_table || !deleted || session->transaction.stmt.modified_non_trans_table);
311
326
  free_underlaid_joins(session, select_lex);
312
327
 
313
 
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
 
328
  int res= (error >= 0 || session->is_error());
 
329
  DRIZZLE_DELETE_END(res, deleted);
314
330
  if (error < 0 || (session->lex->ignore && !session->is_fatal_error))
315
331
  {
316
332
    session->row_count_func= deleted;
317
 
    /**
318
 
     * Resetting the Diagnostic area to prevent
319
 
     * lp bug# 439719
320
 
     */
321
 
    session->main_da.reset_diagnostics_area();    
322
333
    session->my_ok((ha_rows) session->row_count_func);
323
334
  }
324
335
  return (error >= 0 || session->is_error());
325
336
 
326
337
err:
327
 
  DRIZZLE_DELETE_DONE(1, 0);
 
338
  DRIZZLE_DELETE_END(1, 0);
328
339
  return true;
329
340
}
330
341
 
357
368
    return(true);
358
369
  {
359
370
    TableList *duplicate;
360
 
    if ((duplicate= unique_table(table_list, table_list->next_global)))
 
371
    if ((duplicate= unique_table(session, table_list, table_list->next_global, 0)))
361
372
    {
362
373
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
363
374
      return(true);
379
390
/*
380
391
  Optimize delete of all rows by doing a full generate of the table
381
392
  This will work even if the .ISM and .ISD tables are destroyed
 
393
 
 
394
  dont_send_ok should be set if:
 
395
  - We should always wants to generate the table (even if the table type
 
396
    normally can't safely do this.
 
397
  - We don't want an ok to be sent to the end user.
 
398
  - We don't want to log the truncate command
 
399
  - If we want to have a name lock on the table on exit without errors.
382
400
*/
383
401
 
384
 
bool mysql_truncate(Session& session, TableList *table_list)
 
402
bool mysql_truncate(Session *session, TableList *table_list, bool dont_send_ok)
385
403
{
 
404
  HA_CREATE_INFO create_info;
 
405
  char path[FN_REFLEN];
 
406
  Table *table;
386
407
  bool error;
387
 
  TransactionServices &transaction_services= TransactionServices::singleton();
388
 
 
389
 
  uint64_t save_options= session.options;
 
408
  uint32_t path_length;
 
409
 
 
410
 
 
411
  memset(&create_info, 0, sizeof(create_info));
 
412
  /* If it is a temporary table, close and regenerate it */
 
413
  if (!dont_send_ok && (table= session->find_temporary_table(table_list)))
 
414
  {
 
415
    StorageEngine *table_type= table->s->db_type();
 
416
    TableShare *share= table->s;
 
417
 
 
418
    if (!table_type->check_flag(HTON_BIT_CAN_RECREATE))
 
419
      goto trunc_by_del;
 
420
 
 
421
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
 
422
 
 
423
    session->close_temporary_table(table, false, false);    // Don't free share
 
424
    ha_create_table(session, share->normalized_path.str,
 
425
                    share->db.str, share->table_name.str, &create_info, 1,
 
426
                    NULL);
 
427
    // We don't need to call invalidate() because this table is not in cache
 
428
    if ((error= (int) !(session->open_temporary_table(share->path.str,
 
429
                                                      share->db.str,
 
430
                                                      share->table_name.str, 1,
 
431
                                                      OTM_OPEN))))
 
432
      (void) session->rm_temporary_table(table_type, path);
 
433
    share->free_table_share();
 
434
    free((char*) table);
 
435
    /*
 
436
      If we return here we will not have logged the truncation to the bin log
 
437
      and we will not my_ok() to the client.
 
438
    */
 
439
    goto end;
 
440
  }
 
441
 
 
442
  path_length= build_table_filename(path, sizeof(path), table_list->db,
 
443
                                    table_list->table_name, 0);
 
444
 
 
445
  if (!dont_send_ok)
 
446
    goto trunc_by_del;
 
447
 
 
448
  pthread_mutex_lock(&LOCK_open); /* Recreate table for truncate */
 
449
  error= ha_create_table(session, path, table_list->db, table_list->table_name,
 
450
                         &create_info, 1, NULL);
 
451
  pthread_mutex_unlock(&LOCK_open);
 
452
 
 
453
end:
 
454
  if (!dont_send_ok)
 
455
  {
 
456
    if (!error)
 
457
    {
 
458
      /*
 
459
        TRUNCATE must always be statement-based binlogged (not row-based) so
 
460
        we don't test current_stmt_binlog_row_based.
 
461
      */
 
462
      write_bin_log(session, true, session->query, session->query_length);
 
463
      session->my_ok();         // This should return record count
 
464
    }
 
465
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
466
    unlock_table_name(table_list);
 
467
    pthread_mutex_unlock(&LOCK_open);
 
468
  }
 
469
  else if (error)
 
470
  {
 
471
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
472
    unlock_table_name(table_list);
 
473
    pthread_mutex_unlock(&LOCK_open);
 
474
  }
 
475
  return(error);
 
476
 
 
477
trunc_by_del:
 
478
  /* Probably InnoDB table */
 
479
  uint64_t save_options= session->options;
390
480
  table_list->lock_type= TL_WRITE;
391
 
  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
392
 
  mysql_init_select(session.lex);
393
 
  error= mysql_delete(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
 
481
  session->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
 
482
  ha_enable_transaction(session, false);
 
483
  mysql_init_select(session->lex);
 
484
  error= mysql_delete(session, table_list, (COND*) 0, (SQL_LIST*) 0,
394
485
                      HA_POS_ERROR, 0L, true);
 
486
  ha_enable_transaction(session, true);
395
487
  /*
396
488
    Safety, in case the engine ignored ha_enable_transaction(false)
397
489
    above. Also clears session->transaction.*.
398
490
  */
399
 
  error= transaction_services.ha_autocommit_or_rollback(&session, error);
400
 
  session.options= save_options;
401
 
 
402
 
  return error;
 
491
  error= ha_autocommit_or_rollback(session, error);
 
492
  ha_commit(session);
 
493
  session->options= save_options;
 
494
  return(error);
403
495
}
404
 
 
405
 
} /* namespace drizzled */