~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Stewart Smith
  • Author(s): Marko Mäkelä
  • Date: 2010-12-20 03:21:44 UTC
  • mto: (2021.1.2 build)
  • mto: This revision was merged to the branch mainline in revision 2022.
  • Revision ID: stewart@flamingspork.com-20101220032144-7aqh2z403u7d7bdp
Merge Revision revid:marko.makela@oracle.com-20101104131215-pfxnpidlrzd4krg0 from MySQL InnoDB

Original revid:marko.makela@oracle.com-20101104131215-pfxnpidlrzd4krg0

Original Authors: Marko Mäkelä <marko.makela@oracle.com>
Original commit message:
row_ins_index_entry(): Note that only CREATE INDEX sets foreign=FALSE.

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