~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

Cleanup around SAFEMALLOC

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