~xnox/ubuntu/saucy/drizzle/merge

« back to all changes in this revision

Viewing changes to .pc/debian-changes-2010.12.06-0ubuntu4/drizzled/sql_delete.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2011-01-01 13:55:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110101135503-x2ub1akxoisgwi6z
Tags: 2010.12.06-0ubuntu4
* Fixed missing build depends.
* Added Lee to uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
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 */
 
15
 
 
16
/*
 
17
  Delete of records and truncate of tables.
 
18
 
 
19
  Multi-table deletes were introduced by Monty and Sinisa
 
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
{
 
37
 
 
38
/**
 
39
  Implement DELETE SQL word.
 
40
 
 
41
  @note Like implementations of other DDL/DML in MySQL, this function
 
42
  relies on the caller to close the thread tables. This is done in the
 
43
  end of dispatch_command().
 
44
*/
 
45
 
 
46
bool mysql_delete(Session *session, TableList *table_list, COND *conds,
 
47
                  SQL_LIST *order, ha_rows limit, uint64_t,
 
48
                  bool reset_auto_increment)
 
49
{
 
50
  int           error;
 
51
  Table         *table;
 
52
  optimizer::SqlSelect *select= NULL;
 
53
  ReadRecord    info;
 
54
  bool          using_limit=limit != HA_POS_ERROR;
 
55
  bool          transactional_table, const_cond;
 
56
  bool          const_cond_result;
 
57
  ha_rows       deleted= 0;
 
58
  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))
 
63
  {
 
64
    DRIZZLE_DELETE_DONE(1, 0);
 
65
    return true;
 
66
  }
 
67
 
 
68
  table= table_list->table;
 
69
  assert(table);
 
70
 
 
71
  session->set_proc_info("init");
 
72
  table->map=1;
 
73
 
 
74
  if (mysql_prepare_delete(session, table_list, &conds))
 
75
  {
 
76
    DRIZZLE_DELETE_DONE(1, 0);
 
77
    return true;
 
78
  }
 
79
 
 
80
  /* check ORDER BY even if it can be ignored */
 
81
  if (order && order->elements)
 
82
  {
 
83
    TableList   tables;
 
84
    List<Item>   fields;
 
85
    List<Item>   all_fields;
 
86
 
 
87
    tables.table = table;
 
88
    tables.alias = table_list->alias;
 
89
 
 
90
      if (select_lex->setup_ref_array(session, order->elements) ||
 
91
          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
      }
 
100
  }
 
101
 
 
102
  const_cond= (!conds || conds->const_item());
 
103
 
 
104
  select_lex->no_error= session->lex->ignore;
 
105
 
 
106
  const_cond_result= const_cond && (!conds || conds->val_int());
 
107
  if (session->is_error())
 
108
  {
 
109
    /* Error evaluating val_int(). */
 
110
    return(true);
 
111
  }
 
112
 
 
113
  /*
 
114
    Test if the user wants to delete all rows and deletion doesn't have
 
115
    any side-effects (because of triggers), so we can use optimized
 
116
    handler::delete_all_rows() method.
 
117
 
 
118
    We implement fast TRUNCATE for InnoDB even if triggers are
 
119
    present.  TRUNCATE ignores triggers.
 
120
 
 
121
    We can use delete_all_rows() if and only if:
 
122
    - We allow new functions (not using option --skip-new), and are
 
123
      not in safe mode (not using option --safe-mode)
 
124
    - There is no limit clause
 
125
    - The condition is constant
 
126
    - If there is a condition, then it it produces a non-zero value
 
127
    - If the current command is DELETE FROM with no where clause
 
128
      (i.e., not TRUNCATE) then:
 
129
      - We should not be binlogging this statement row-based, and
 
130
      - there should be no delete triggers associated with the table.
 
131
  */
 
132
  if (!using_limit && const_cond_result)
 
133
  {
 
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()))
 
138
    {
 
139
      error= -1;                                // ok
 
140
      deleted= maybe_deleted;
 
141
      goto cleanup;
 
142
    }
 
143
    if (error != HA_ERR_WRONG_COMMAND)
 
144
    {
 
145
      table->print_error(error,MYF(0));
 
146
      error=0;
 
147
      goto cleanup;
 
148
    }
 
149
    /* Handler didn't support fast delete; Delete rows one by one */
 
150
  }
 
151
  if (conds)
 
152
  {
 
153
    Item::cond_result result;
 
154
    conds= remove_eq_conds(session, conds, &result);
 
155
    if (result == Item::COND_FALSE)             // Impossible where
 
156
      limit= 0;
 
157
  }
 
158
 
 
159
  /* Update the table->cursor->stats.records number */
 
160
  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
 
161
 
 
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);
 
165
  if (error)
 
166
  {
 
167
    DRIZZLE_DELETE_DONE(1, 0);
 
168
    return true;
 
169
  }
 
170
 
 
171
  if ((select && select->check_quick(session, false, limit)) || !limit)
 
172
  {
 
173
    delete select;
 
174
    free_underlaid_joins(session, select_lex);
 
175
    session->row_count_func= 0;
 
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);
 
183
    /*
 
184
      We don't need to call reset_auto_increment in this case, because
 
185
      mysql_truncate always gives a NULL conds argument, hence we never
 
186
      get here.
 
187
    */
 
188
    return 0; // Nothing to delete
 
189
  }
 
190
 
 
191
  /* If running in safe sql mode, don't allow updates without keys */
 
192
  if (table->quick_keys.none())
 
193
  {
 
194
    session->server_status|=SERVER_QUERY_NO_INDEX_USED;
 
195
  }
 
196
 
 
197
  if (order && order->elements)
 
198
  {
 
199
    uint32_t         length= 0;
 
200
    SortField  *sortorder;
 
201
    ha_rows examined_rows;
 
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);
 
205
 
 
206
    if (usable_index == MAX_KEY)
 
207
    {
 
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)
 
216
      {
 
217
        delete select;
 
218
        free_underlaid_joins(session, &session->lex->select_lex);
 
219
 
 
220
        DRIZZLE_DELETE_DONE(1, 0);
 
221
        return true;
 
222
      }
 
223
      /*
 
224
        Filesort has already found and selected the rows we want to delete,
 
225
        so we don't need the where clause
 
226
      */
 
227
      delete select;
 
228
      free_underlaid_joins(session, select_lex);
 
229
      select= 0;
 
230
    }
 
231
  }
 
232
 
 
233
  /* If quick select is used, initialize it before retrieving rows. */
 
234
  if (select && select->quick && select->quick->reset())
 
235
  {
 
236
    delete select;
 
237
    free_underlaid_joins(session, select_lex);
 
238
    DRIZZLE_DELETE_DONE(1, 0);
 
239
    return true;
 
240
  }
 
241
 
 
242
  if (usable_index==MAX_KEY)
 
243
  {
 
244
    info.init_read_record(session,table,select,1,1);
 
245
  }
 
246
  else
 
247
  {
 
248
    info.init_read_record_idx(session, table, 1, usable_index);
 
249
  }
 
250
 
 
251
  session->set_proc_info("updating");
 
252
 
 
253
  table->mark_columns_needed_for_delete();
 
254
 
 
255
  while (!(error=info.read_record(&info)) && !session->getKilled() &&
 
256
         ! session->is_error())
 
257
  {
 
258
    // session->is_error() is tested to disallow delete row on error
 
259
    if (!(select && select->skip_record())&& ! session->is_error() )
 
260
    {
 
261
      if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
 
262
      {
 
263
        deleted++;
 
264
        if (!--limit && using_limit)
 
265
        {
 
266
          error= -1;
 
267
          break;
 
268
        }
 
269
      }
 
270
      else
 
271
      {
 
272
        table->print_error(error,MYF(0));
 
273
        /*
 
274
          In < 4.0.14 we set the error number to 0 here, but that
 
275
          was not sensible, because then MySQL would not roll back the
 
276
          failed DELETE, and also wrote it to the binlog. For MyISAM
 
277
          tables a DELETE probably never should fail (?), but for
 
278
          InnoDB it can fail in a FOREIGN KEY error or an
 
279
          out-of-tablespace error.
 
280
        */
 
281
        error= 1;
 
282
        break;
 
283
      }
 
284
    }
 
285
    else
 
286
      table->cursor->unlock_row();  // Row failed selection, release lock on it
 
287
  }
 
288
  killed_status= session->getKilled();
 
289
  if (killed_status != Session::NOT_KILLED || session->is_error())
 
290
    error= 1;                                   // Aborted
 
291
 
 
292
  session->set_proc_info("end");
 
293
  info.end_read_record();
 
294
 
 
295
cleanup:
 
296
 
 
297
  if (reset_auto_increment && (error < 0))
 
298
  {
 
299
    /*
 
300
      We're really doing a truncate and need to reset the table's
 
301
      auto-increment counter.
 
302
    */
 
303
    int error2= table->cursor->ha_reset_auto_increment(0);
 
304
 
 
305
    if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
 
306
    {
 
307
      table->print_error(error2, MYF(0));
 
308
      error= 1;
 
309
    }
 
310
  }
 
311
 
 
312
  delete select;
 
313
  transactional_table= table->cursor->has_transactions();
 
314
 
 
315
  if (!transactional_table && deleted > 0)
 
316
    session->transaction.stmt.markModifiedNonTransData();
 
317
 
 
318
  /* See similar binlogging code in sql_update.cc, for comments */
 
319
  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
 
320
  {
 
321
    if (session->transaction.stmt.hasModifiedNonTransData())
 
322
      session->transaction.all.markModifiedNonTransData();
 
323
  }
 
324
  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
 
325
  free_underlaid_joins(session, select_lex);
 
326
 
 
327
  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
 
328
  if (error < 0 || (session->lex->ignore && !session->is_fatal_error))
 
329
  {
 
330
    session->row_count_func= deleted;
 
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);
 
337
  }
 
338
  session->status_var.deleted_row_count+= deleted;
 
339
 
 
340
  return (error >= 0 || session->is_error());
 
341
}
 
342
 
 
343
 
 
344
/*
 
345
  Prepare items in DELETE statement
 
346
 
 
347
  SYNOPSIS
 
348
    mysql_prepare_delete()
 
349
    session                     - thread handler
 
350
    table_list          - global/local table list
 
351
    conds               - conditions
 
352
 
 
353
  RETURN VALUE
 
354
    false OK
 
355
    true  error
 
356
*/
 
357
int mysql_prepare_delete(Session *session, TableList *table_list, Item **conds)
 
358
{
 
359
  Select_Lex *select_lex= &session->lex->select_lex;
 
360
 
 
361
  List<Item> all_fields;
 
362
 
 
363
  session->lex->allow_sum_func= 0;
 
364
  if (setup_tables_and_check_access(session, &session->lex->select_lex.context,
 
365
                                    &session->lex->select_lex.top_join_list,
 
366
                                    table_list,
 
367
                                    &select_lex->leaf_tables, false) ||
 
368
      session->setup_conds(table_list, conds))
 
369
    return(true);
 
370
  {
 
371
    TableList *duplicate;
 
372
    if ((duplicate= unique_table(table_list, table_list->next_global)))
 
373
    {
 
374
      my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
 
375
      return(true);
 
376
    }
 
377
  }
 
378
 
 
379
  if (select_lex->inner_refs_list.elements &&
 
380
    fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
 
381
    return(-1);
 
382
 
 
383
  return(false);
 
384
}
 
385
 
 
386
 
 
387
/***************************************************************************
 
388
  TRUNCATE Table
 
389
****************************************************************************/
 
390
 
 
391
/*
 
392
  Optimize delete of all rows by doing a full generate of the table
 
393
  This will work even if the .ISM and .ISD tables are destroyed
 
394
*/
 
395
 
 
396
bool mysql_truncate(Session& session, TableList *table_list)
 
397
{
 
398
  bool error;
 
399
  TransactionServices &transaction_services= TransactionServices::singleton();
 
400
 
 
401
  uint64_t save_options= session.options;
 
402
  table_list->lock_type= TL_WRITE;
 
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,
 
406
                      HA_POS_ERROR, 0L, true);
 
407
  /*
 
408
    Safety, in case the engine ignored ha_enable_transaction(false)
 
409
    above. Also clears session->transaction.*.
 
410
  */
 
411
  error= transaction_services.autocommitOrRollback(&session, error);
 
412
  session.options= save_options;
 
413
 
 
414
  return error;
 
415
}
 
416
 
 
417
} /* namespace drizzled */