~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Brian Aker
  • Date: 2010-01-22 00:53:13 UTC
  • Revision ID: brian@gaz-20100122005313-jmizcbcdi1lt4tcx
Revert db patch.

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