~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

Cleaned up a few global tests which aren't happy now.

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"
 
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>
 
28
#include "drizzled/probes.h"
34
29
 
35
 
namespace drizzled
36
 
{
 
30
using namespace drizzled;
37
31
 
38
32
/**
39
33
  Implement DELETE SQL word.
43
37
  end of dispatch_command().
44
38
*/
45
39
 
46
 
bool delete_query(Session *session, TableList *table_list, COND *conds,
47
 
                  SQL_LIST *order, ha_rows limit, uint64_t,
 
40
bool mysql_delete(Session *session, TableList *table_list, COND *conds,
 
41
                  SQL_LIST *order, ha_rows limit, uint64_t options,
48
42
                  bool reset_auto_increment)
49
43
{
50
 
  int           error;
 
44
  bool          will_batch;
 
45
  int           error, loc_error;
51
46
  Table         *table;
52
 
  optimizer::SqlSelect *select= NULL;
53
 
  ReadRecord    info;
 
47
  SQL_SELECT    *select=0;
 
48
  READ_RECORD   info;
54
49
  bool          using_limit=limit != HA_POS_ERROR;
55
 
  bool          transactional_table, const_cond;
 
50
  bool          transactional_table, safe_update, const_cond;
56
51
  bool          const_cond_result;
57
52
  ha_rows       deleted= 0;
58
53
  uint32_t usable_index= MAX_KEY;
59
54
  Select_Lex   *select_lex= &session->lex->select_lex;
60
 
  Session::killed_state_t killed_status= Session::NOT_KILLED;
 
55
  Session::killed_state killed_status= Session::NOT_KILLED;
61
56
 
62
57
  if (session->openTablesLock(table_list))
63
58
  {
71
66
  session->set_proc_info("init");
72
67
  table->map=1;
73
68
 
74
 
  if (prepare_delete(session, table_list, &conds))
75
 
  {
76
 
    DRIZZLE_DELETE_DONE(1, 0);
77
 
    return true;
78
 
  }
 
69
  if (mysql_prepare_delete(session, table_list, &conds))
 
70
    goto err;
79
71
 
80
72
  /* check ORDER BY even if it can be ignored */
81
73
  if (order && order->elements)
84
76
    List<Item>   fields;
85
77
    List<Item>   all_fields;
86
78
 
 
79
    memset(&tables, 0, sizeof(tables));
87
80
    tables.table = table;
88
81
    tables.alias = table_list->alias;
89
82
 
90
83
      if (select_lex->setup_ref_array(session, order->elements) ||
91
84
          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
 
      }
 
85
                    fields, all_fields, (order_st*) order->first))
 
86
    {
 
87
      delete select;
 
88
      free_underlaid_joins(session, &session->lex->select_lex);
 
89
      goto err;
 
90
    }
100
91
  }
101
92
 
102
93
  const_cond= (!conds || conds->const_item());
 
94
  safe_update=test(session->options & OPTION_SAFE_UPDATES);
 
95
  if (safe_update && const_cond)
 
96
  {
 
97
    my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
98
               ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
99
    goto err;
 
100
  }
103
101
 
104
102
  select_lex->no_error= session->lex->ignore;
105
103
 
131
129
  */
132
130
  if (!using_limit && const_cond_result)
133
131
  {
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()))
 
132
    /* Update the table->file->stats.records number */
 
133
    table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
134
    ha_rows const maybe_deleted= table->file->stats.records;
 
135
    if (!(error=table->file->ha_delete_all_rows()))
138
136
    {
139
137
      error= -1;                                // ok
140
138
      deleted= maybe_deleted;
142
140
    }
143
141
    if (error != HA_ERR_WRONG_COMMAND)
144
142
    {
145
 
      table->print_error(error,MYF(0));
 
143
      table->file->print_error(error,MYF(0));
146
144
      error=0;
147
145
      goto cleanup;
148
146
    }
156
154
      limit= 0;
157
155
  }
158
156
 
159
 
  /* Update the table->cursor->stats.records number */
160
 
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
157
  /* Update the table->file->stats.records number */
 
158
  table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
161
159
 
162
160
  table->covering_keys.reset();
163
161
  table->quick_keys.reset();            // Can't use 'only index'
164
 
  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
 
162
  select=make_select(table, 0, 0, conds, 0, &error);
165
163
  if (error)
166
 
  {
167
 
    DRIZZLE_DELETE_DONE(1, 0);
168
 
    return true;
169
 
  }
170
 
 
171
 
  if ((select && select->check_quick(session, false, limit)) || !limit)
 
164
    goto err;
 
165
  if ((select && select->check_quick(session, safe_update, limit)) || !limit)
172
166
  {
173
167
    delete select;
174
168
    free_underlaid_joins(session, select_lex);
175
169
    session->row_count_func= 0;
176
 
    if (session->is_error())
177
 
      return true;
178
170
    DRIZZLE_DELETE_DONE(0, 0);
179
171
    /**
180
172
     * Resetting the Diagnostic area to prevent
181
173
     * lp bug# 439719
182
174
     */
183
175
    session->main_da.reset_diagnostics_area();
184
 
    session->my_ok((ha_rows) session->rowCount());
 
176
    session->my_ok((ha_rows) session->row_count_func);
185
177
    /*
186
178
      We don't need to call reset_auto_increment in this case, because
187
179
      mysql_truncate always gives a NULL conds argument, hence we never
194
186
  if (table->quick_keys.none())
195
187
  {
196
188
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
189
    if (safe_update && !using_limit)
 
190
    {
 
191
      delete select;
 
192
      free_underlaid_joins(session, select_lex);
 
193
      my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
 
194
                 ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
 
195
      goto err;
 
196
    }
197
197
  }
 
198
  if (options & OPTION_QUICK)
 
199
    (void) table->file->extra(HA_EXTRA_QUICK);
198
200
 
199
201
  if (order && order->elements)
200
202
  {
201
203
    uint32_t         length= 0;
202
 
    SortField  *sortorder;
 
204
    SORT_FIELD  *sortorder;
203
205
    ha_rows examined_rows;
204
206
 
205
207
    if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
206
 
      usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
 
208
      usable_index= get_index_for_order(table, (order_st*)(order->first), limit);
207
209
 
208
210
    if (usable_index == MAX_KEY)
209
211
    {
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)
 
212
      table->sort.io_cache= new IO_CACHE;
 
213
      memset(table->sort.io_cache, 0, sizeof(IO_CACHE));
 
214
 
 
215
 
 
216
      if (!(sortorder= make_unireg_sortorder((order_st*) order->first,
 
217
                                             &length, NULL)) ||
 
218
          (table->sort.found_records = filesort(session, table, sortorder, length,
 
219
                                                select, HA_POS_ERROR, 1,
 
220
                                                &examined_rows))
 
221
          == HA_POS_ERROR)
218
222
      {
219
223
        delete select;
220
224
        free_underlaid_joins(session, &session->lex->select_lex);
221
 
 
222
 
        DRIZZLE_DELETE_DONE(1, 0);
223
 
        return true;
 
225
        goto err;
224
226
      }
225
227
      /*
226
228
        Filesort has already found and selected the rows we want to delete,
237
239
  {
238
240
    delete select;
239
241
    free_underlaid_joins(session, select_lex);
240
 
    DRIZZLE_DELETE_DONE(1, 0);
241
 
    return true;
 
242
    goto err;
242
243
  }
243
 
 
244
244
  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
 
  }
 
245
    init_read_record(&info,session,table,select,1,1);
254
246
  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
 
  }
 
247
    init_read_record_idx(&info, session, table, 1, usable_index);
264
248
 
265
249
  session->set_proc_info("updating");
266
250
 
 
251
  will_batch= !table->file->start_bulk_delete();
 
252
 
 
253
 
267
254
  table->mark_columns_needed_for_delete();
268
255
 
269
 
  while (!(error=info.read_record(&info)) && !session->getKilled() &&
 
256
  while (!(error=info.read_record(&info)) && !session->killed &&
270
257
         ! session->is_error())
271
258
  {
272
259
    // session->is_error() is tested to disallow delete row on error
273
260
    if (!(select && select->skip_record())&& ! session->is_error() )
274
261
    {
275
 
      if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
 
262
      if (!(error= table->file->ha_delete_row(table->record[0])))
276
263
      {
277
264
        deleted++;
278
265
        if (!--limit && using_limit)
283
270
      }
284
271
      else
285
272
      {
286
 
        table->print_error(error,MYF(0));
 
273
        table->file->print_error(error,MYF(0));
287
274
        /*
288
275
          In < 4.0.14 we set the error number to 0 here, but that
289
276
          was not sensible, because then MySQL would not roll back the
297
284
      }
298
285
    }
299
286
    else
300
 
      table->cursor->unlock_row();  // Row failed selection, release lock on it
 
287
      table->file->unlock_row();  // Row failed selection, release lock on it
301
288
  }
302
 
  killed_status= session->getKilled();
 
289
  killed_status= session->killed;
303
290
  if (killed_status != Session::NOT_KILLED || session->is_error())
304
291
    error= 1;                                   // Aborted
305
 
 
 
292
  if (will_batch && (loc_error= table->file->end_bulk_delete()))
 
293
  {
 
294
    if (error != 1)
 
295
      table->file->print_error(loc_error,MYF(0));
 
296
    error=1;
 
297
  }
306
298
  session->set_proc_info("end");
307
 
  info.end_read_record();
308
 
 
309
 
cleanup:
 
299
  end_read_record(&info);
 
300
  if (options & OPTION_QUICK)
 
301
    (void) table->file->extra(HA_EXTRA_NORMAL);
310
302
 
311
303
  if (reset_auto_increment && (error < 0))
312
304
  {
314
306
      We're really doing a truncate and need to reset the table's
315
307
      auto-increment counter.
316
308
    */
317
 
    int error2= table->cursor->ha_reset_auto_increment(0);
 
309
    int error2= table->file->ha_reset_auto_increment(0);
318
310
 
319
311
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
320
312
    {
321
 
      table->print_error(error2, MYF(0));
 
313
      table->file->print_error(error2, MYF(0));
322
314
      error= 1;
323
315
    }
324
316
  }
325
317
 
 
318
cleanup:
 
319
 
326
320
  delete select;
327
 
  transactional_table= table->cursor->has_transactions();
 
321
  transactional_table= table->file->has_transactions();
328
322
 
329
323
  if (!transactional_table && deleted > 0)
330
 
    session->transaction.stmt.markModifiedNonTransData();
 
324
    session->transaction.stmt.modified_non_trans_table= true;
331
325
 
332
326
  /* See similar binlogging code in sql_update.cc, for comments */
333
 
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
 
327
  if ((error < 0) || session->transaction.stmt.modified_non_trans_table)
334
328
  {
335
 
    if (session->transaction.stmt.hasModifiedNonTransData())
336
 
      session->transaction.all.markModifiedNonTransData();
 
329
    if (session->transaction.stmt.modified_non_trans_table)
 
330
      session->transaction.all.modified_non_trans_table= true;
337
331
  }
338
 
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
 
332
  assert(transactional_table || !deleted || session->transaction.stmt.modified_non_trans_table);
339
333
  free_underlaid_joins(session, select_lex);
340
334
 
341
335
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
347
341
     * lp bug# 439719
348
342
     */
349
343
    session->main_da.reset_diagnostics_area();    
350
 
    session->my_ok((ha_rows) session->rowCount());
 
344
    session->my_ok((ha_rows) session->row_count_func);
351
345
  }
352
 
  session->status_var.deleted_row_count+= deleted;
353
 
 
354
346
  return (error >= 0 || session->is_error());
 
347
 
 
348
err:
 
349
  DRIZZLE_DELETE_DONE(1, 0);
 
350
  return true;
355
351
}
356
352
 
357
353
 
359
355
  Prepare items in DELETE statement
360
356
 
361
357
  SYNOPSIS
362
 
    prepare_delete()
 
358
    mysql_prepare_delete()
363
359
    session                     - thread handler
364
360
    table_list          - global/local table list
365
361
    conds               - conditions
368
364
    false OK
369
365
    true  error
370
366
*/
371
 
int prepare_delete(Session *session, TableList *table_list, Item **conds)
 
367
int mysql_prepare_delete(Session *session, TableList *table_list, Item **conds)
372
368
{
373
369
  Select_Lex *select_lex= &session->lex->select_lex;
374
370
 
383
379
    return(true);
384
380
  {
385
381
    TableList *duplicate;
386
 
    if ((duplicate= unique_table(table_list, table_list->next_global)))
 
382
    if ((duplicate= unique_table(session, table_list, table_list->next_global, 0)))
387
383
    {
388
384
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
389
385
      return(true);
392
388
 
393
389
  if (select_lex->inner_refs_list.elements &&
394
390
    fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
395
 
    return(true);
 
391
    return(-1);
396
392
 
397
393
  return(false);
398
394
}
405
401
/*
406
402
  Optimize delete of all rows by doing a full generate of the table
407
403
  This will work even if the .ISM and .ISD tables are destroyed
 
404
 
 
405
  dont_send_ok should be set if:
 
406
  - We should always wants to generate the table (even if the table type
 
407
    normally can't safely do this.
 
408
  - We don't want an ok to be sent to the end user.
 
409
  - We don't want to log the truncate command
 
410
  - If we want to have a name lock on the table on exit without errors.
408
411
*/
409
412
 
410
 
bool truncate(Session& session, TableList *table_list)
 
413
bool mysql_truncate(Session& session, TableList *table_list, bool dont_send_ok)
411
414
{
 
415
  HA_CREATE_INFO create_info;
 
416
  char path[FN_REFLEN];
 
417
  Table *table;
412
418
  bool error;
413
 
  TransactionServices &transaction_services= TransactionServices::singleton();
414
 
 
 
419
  uint32_t path_length;
 
420
  message::Table tmp_table;
 
421
 
 
422
 
 
423
  memset(&create_info, 0, sizeof(create_info));
 
424
  /* If it is a temporary table, close and regenerate it */
 
425
  if (!dont_send_ok && (table= session.find_temporary_table(table_list)))
 
426
  {
 
427
    message::Table::StorageEngine *engine= tmp_table.mutable_engine();
 
428
    plugin::StorageEngine *table_type= table->s->db_type();
 
429
    TableShare *share= table->s;
 
430
 
 
431
    if (!table_type->check_flag(HTON_BIT_CAN_RECREATE))
 
432
      goto trunc_by_del;
 
433
 
 
434
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
 
435
 
 
436
    /*
 
437
      Because we bypass "all" of what it takes to create a Table we are on shakey ground in this
 
438
      execution path. Not everything will be properly created in order to use the table
 
439
      we create here. 
 
440
 
 
441
      Painful.
 
442
    */
 
443
    assert(share->storage_engine);
 
444
    session.close_temporary_table(table, false, false);    // Don't free share
 
445
    assert(share->storage_engine);
 
446
    engine->set_name(share->db_type()->getName());
 
447
    plugin::StorageEngine::createTable(session, share->normalized_path.str,
 
448
                                       share->db.str, share->table_name.str, create_info, 
 
449
                                       true, tmp_table, false);
 
450
    // We don't need to call invalidate() because this table is not in cache
 
451
    if ((error= (int) !(session.open_temporary_table(share->path.str,
 
452
                                                      share->db.str,
 
453
                                                      share->table_name.str, 1,
 
454
                                                      OTM_OPEN))))
 
455
      (void) session.rm_temporary_table(table_type, path);
 
456
    share->free_table_share();
 
457
    free((char*) table);
 
458
    /*
 
459
      If we return here we will not have logged the truncation to the bin log
 
460
      and we will not my_ok() to the client.
 
461
    */
 
462
    goto end;
 
463
  }
 
464
 
 
465
  path_length= build_table_filename(path, sizeof(path), table_list->db,
 
466
                                    table_list->table_name, 0);
 
467
 
 
468
  if (!dont_send_ok)
 
469
    goto trunc_by_del;
 
470
 
 
471
  pthread_mutex_lock(&LOCK_open); /* Recreate table for truncate */
 
472
  error= plugin::StorageEngine::createTable(session, path, table_list->db, table_list->table_name,
 
473
                                            create_info, true, tmp_table, false);
 
474
  pthread_mutex_unlock(&LOCK_open);
 
475
 
 
476
end:
 
477
  if (!dont_send_ok)
 
478
  {
 
479
    if (!error)
 
480
    {
 
481
      /*
 
482
        TRUNCATE must always be statement-based binlogged (not row-based) so
 
483
        we don't test current_stmt_binlog_row_based.
 
484
      */
 
485
      write_bin_log(&session, session.query, session.query_length);
 
486
      session.my_ok();          // This should return record count
 
487
    }
 
488
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
489
    unlock_table_name(table_list);
 
490
    pthread_mutex_unlock(&LOCK_open);
 
491
  }
 
492
  else if (error)
 
493
  {
 
494
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
495
    unlock_table_name(table_list);
 
496
    pthread_mutex_unlock(&LOCK_open);
 
497
  }
 
498
  return(error);
 
499
 
 
500
trunc_by_del:
 
501
  /* Probably InnoDB table */
415
502
  uint64_t save_options= session.options;
416
503
  table_list->lock_type= TL_WRITE;
417
504
  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
418
 
  init_select(session.lex);
419
 
  error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
 
505
  ha_enable_transaction(&session, false);
 
506
  mysql_init_select(session.lex);
 
507
  error= mysql_delete(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
420
508
                      HA_POS_ERROR, 0L, true);
 
509
  ha_enable_transaction(&session, true);
421
510
  /*
422
511
    Safety, in case the engine ignored ha_enable_transaction(false)
423
512
    above. Also clears session->transaction.*.
424
513
  */
425
 
  error= transaction_services.autocommitOrRollback(session, error);
 
514
  error= ha_autocommit_or_rollback(&session, error);
 
515
  ha_commit(&session);
426
516
  session.options= save_options;
427
517
 
428
 
  return error;
 
518
  return(error);
429
519
}
430
 
 
431
 
} /* namespace drizzled */