~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_delete.cc

  • Committer: Monty Taylor
  • Date: 2008-12-17 04:54:32 UTC
  • mto: (685.1.38 devel) (713.1.1 devel)
  • mto: This revision was merged to the branch mainline in revision 713.
  • Revision ID: monty@inaugust.com-20081217045432-dw4425razy7do46i
Fixed bool. No more sql_mode.

Show diffs side-by-side

added added

removed removed

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