~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Brian Aker
  • Date: 2009-08-18 07:20:29 UTC
  • mfrom: (1117.1.9 merge)
  • Revision ID: brian@gaz-20090818072029-s9ch5lcmltxwidn7
Merge of Brian

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;
 
51
  Select_Lex   *select_lex= &session->lex->select_lex;
 
52
  Session::killed_state killed_status= Session::NOT_KILLED;
 
53
 
61
54
 
62
55
  if (session->openTablesLock(table_list))
63
 
  {
64
 
    DRIZZLE_DELETE_DONE(1, 0);
65
56
    return true;
66
 
  }
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
363
      session->setup_conds(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
}
405
386
/*
406
387
  Optimize delete of all rows by doing a full generate of the table
407
388
  This will work even if the .ISM and .ISD tables are destroyed
 
389
 
 
390
  dont_send_ok should be set if:
 
391
  - We should always wants to generate the table (even if the table type
 
392
    normally can't safely do this.
 
393
  - We don't want an ok to be sent to the end user.
 
394
  - We don't want to log the truncate command
 
395
  - If we want to have a name lock on the table on exit without errors.
408
396
*/
409
397
 
410
 
bool truncate(Session& session, TableList *table_list)
 
398
bool mysql_truncate(Session *session, TableList *table_list, bool dont_send_ok)
411
399
{
 
400
  HA_CREATE_INFO create_info;
 
401
  char path[FN_REFLEN];
 
402
  Table *table;
412
403
  bool error;
413
 
  TransactionServices &transaction_services= TransactionServices::singleton();
414
 
 
415
 
  uint64_t save_options= session.options;
 
404
  uint32_t path_length;
 
405
 
 
406
 
 
407
  memset(&create_info, 0, sizeof(create_info));
 
408
  /* If it is a temporary table, close and regenerate it */
 
409
  if (!dont_send_ok && (table= session->find_temporary_table(table_list)))
 
410
  {
 
411
    StorageEngine *table_type= table->s->db_type();
 
412
    TableShare *share= table->s;
 
413
 
 
414
    if (!table_type->check_flag(HTON_BIT_CAN_RECREATE))
 
415
      goto trunc_by_del;
 
416
 
 
417
    table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
 
418
 
 
419
    session->close_temporary_table(table, false, false);    // Don't free share
 
420
    ha_create_table(session, share->normalized_path.str,
 
421
                    share->db.str, share->table_name.str, &create_info, 1,
 
422
                    NULL);
 
423
    // We don't need to call invalidate() because this table is not in cache
 
424
    if ((error= (int) !(session->open_temporary_table(share->path.str,
 
425
                                                      share->db.str,
 
426
                                                      share->table_name.str, 1,
 
427
                                                      OTM_OPEN))))
 
428
      (void) session->rm_temporary_table(table_type, path);
 
429
    share->free_table_share();
 
430
    free((char*) table);
 
431
    /*
 
432
      If we return here we will not have logged the truncation to the bin log
 
433
      and we will not my_ok() to the client.
 
434
    */
 
435
    goto end;
 
436
  }
 
437
 
 
438
  path_length= build_table_filename(path, sizeof(path), table_list->db,
 
439
                                    table_list->table_name, 0);
 
440
 
 
441
  if (!dont_send_ok)
 
442
    goto trunc_by_del;
 
443
 
 
444
  pthread_mutex_lock(&LOCK_open); /* Recreate table for truncate */
 
445
  error= ha_create_table(session, path, table_list->db, table_list->table_name,
 
446
                         &create_info, 1, NULL);
 
447
  pthread_mutex_unlock(&LOCK_open);
 
448
 
 
449
end:
 
450
  if (!dont_send_ok)
 
451
  {
 
452
    if (!error)
 
453
    {
 
454
      /*
 
455
        TRUNCATE must always be statement-based binlogged (not row-based) so
 
456
        we don't test current_stmt_binlog_row_based.
 
457
      */
 
458
      write_bin_log(session, true, session->query, session->query_length);
 
459
      session->my_ok();         // This should return record count
 
460
    }
 
461
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
462
    unlock_table_name(table_list);
 
463
    pthread_mutex_unlock(&LOCK_open);
 
464
  }
 
465
  else if (error)
 
466
  {
 
467
    pthread_mutex_lock(&LOCK_open); /* For truncate delete from hash when finished */
 
468
    unlock_table_name(table_list);
 
469
    pthread_mutex_unlock(&LOCK_open);
 
470
  }
 
471
  return(error);
 
472
 
 
473
trunc_by_del:
 
474
  /* Probably InnoDB table */
 
475
  uint64_t save_options= session->options;
416
476
  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,
 
477
  session->options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
 
478
  ha_enable_transaction(session, false);
 
479
  mysql_init_select(session->lex);
 
480
  error= mysql_delete(session, table_list, (COND*) 0, (SQL_LIST*) 0,
420
481
                      HA_POS_ERROR, 0L, true);
 
482
  ha_enable_transaction(session, true);
421
483
  /*
422
484
    Safety, in case the engine ignored ha_enable_transaction(false)
423
485
    above. Also clears session->transaction.*.
424
486
  */
425
 
  error= transaction_services.autocommitOrRollback(session, error);
426
 
  session.options= save_options;
427
 
 
428
 
  return error;
 
487
  error= ha_autocommit_or_rollback(session, error);
 
488
  ha_commit(session);
 
489
  session->options= save_options;
 
490
  return(error);
429
491
}
430
 
 
431
 
} /* namespace drizzled */