1
/* Copyright (C) 2000 MySQL AB
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.
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.
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 */
17
Delete of records and truncate of tables.
19
Multi-table deletes were introduced by Monty and Sinisa
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"
39
Implement DELETE SQL word.
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().
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)
52
optimizer::SqlSelect *select= NULL;
54
bool using_limit=limit != HA_POS_ERROR;
55
bool transactional_table, const_cond;
56
bool const_cond_result;
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;
62
if (session->openTablesLock(table_list))
64
DRIZZLE_DELETE_DONE(1, 0);
68
table= table_list->table;
71
session->set_proc_info("init");
74
if (mysql_prepare_delete(session, table_list, &conds))
76
DRIZZLE_DELETE_DONE(1, 0);
80
/* check ORDER BY even if it can be ignored */
81
if (order && order->elements)
85
List<Item> all_fields;
88
tables.alias = table_list->alias;
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))
95
free_underlaid_joins(session, &session->lex->select_lex);
96
DRIZZLE_DELETE_DONE(1, 0);
102
const_cond= (!conds || conds->const_item());
104
select_lex->no_error= session->lex->ignore;
106
const_cond_result= const_cond && (!conds || conds->val_int());
107
if (session->is_error())
109
/* Error evaluating val_int(). */
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.
118
We implement fast TRUNCATE for InnoDB even if triggers are
119
present. TRUNCATE ignores triggers.
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.
132
if (!using_limit && const_cond_result)
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()))
140
deleted= maybe_deleted;
143
if (error != HA_ERR_WRONG_COMMAND)
145
table->print_error(error,MYF(0));
149
/* Handler didn't support fast delete; Delete rows one by one */
153
Item::cond_result result;
154
conds= remove_eq_conds(session, conds, &result);
155
if (result == Item::COND_FALSE) // Impossible where
159
/* Update the table->cursor->stats.records number */
160
table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
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);
167
DRIZZLE_DELETE_DONE(1, 0);
171
if ((select && select->check_quick(session, false, limit)) || !limit)
174
free_underlaid_joins(session, select_lex);
175
session->row_count_func= 0;
176
DRIZZLE_DELETE_DONE(0, 0);
178
* Resetting the Diagnostic area to prevent
181
session->main_da.reset_diagnostics_area();
182
session->my_ok((ha_rows) session->row_count_func);
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
188
return 0; // Nothing to delete
191
/* If running in safe sql mode, don't allow updates without keys */
192
if (table->quick_keys.none())
194
session->server_status|=SERVER_QUERY_NO_INDEX_USED;
197
if (order && order->elements)
200
SortField *sortorder;
201
ha_rows examined_rows;
203
if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
204
usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
206
if (usable_index == MAX_KEY)
208
FileSort filesort(*session);
209
table->sort.io_cache= new internal::IO_CACHE;
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)
218
free_underlaid_joins(session, &session->lex->select_lex);
220
DRIZZLE_DELETE_DONE(1, 0);
224
Filesort has already found and selected the rows we want to delete,
225
so we don't need the where clause
228
free_underlaid_joins(session, select_lex);
233
/* If quick select is used, initialize it before retrieving rows. */
234
if (select && select->quick && select->quick->reset())
237
free_underlaid_joins(session, select_lex);
238
DRIZZLE_DELETE_DONE(1, 0);
242
if (usable_index==MAX_KEY)
244
info.init_read_record(session,table,select,1,1);
248
info.init_read_record_idx(session, table, 1, usable_index);
251
session->set_proc_info("updating");
253
table->mark_columns_needed_for_delete();
255
while (!(error=info.read_record(&info)) && !session->getKilled() &&
256
! session->is_error())
258
// session->is_error() is tested to disallow delete row on error
259
if (!(select && select->skip_record())&& ! session->is_error() )
261
if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
264
if (!--limit && using_limit)
272
table->print_error(error,MYF(0));
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.
286
table->cursor->unlock_row(); // Row failed selection, release lock on it
288
killed_status= session->getKilled();
289
if (killed_status != Session::NOT_KILLED || session->is_error())
292
session->set_proc_info("end");
293
info.end_read_record();
297
if (reset_auto_increment && (error < 0))
300
We're really doing a truncate and need to reset the table's
301
auto-increment counter.
303
int error2= table->cursor->ha_reset_auto_increment(0);
305
if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
307
table->print_error(error2, MYF(0));
313
transactional_table= table->cursor->has_transactions();
315
if (!transactional_table && deleted > 0)
316
session->transaction.stmt.markModifiedNonTransData();
318
/* See similar binlogging code in sql_update.cc, for comments */
319
if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
321
if (session->transaction.stmt.hasModifiedNonTransData())
322
session->transaction.all.markModifiedNonTransData();
324
assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
325
free_underlaid_joins(session, select_lex);
327
DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
328
if (error < 0 || (session->lex->ignore && !session->is_fatal_error))
330
session->row_count_func= deleted;
332
* Resetting the Diagnostic area to prevent
335
session->main_da.reset_diagnostics_area();
336
session->my_ok((ha_rows) session->row_count_func);
338
session->status_var.deleted_row_count+= deleted;
340
return (error >= 0 || session->is_error());
345
Prepare items in DELETE statement
348
mysql_prepare_delete()
349
session - thread handler
350
table_list - global/local table list
357
int mysql_prepare_delete(Session *session, TableList *table_list, Item **conds)
359
Select_Lex *select_lex= &session->lex->select_lex;
361
List<Item> all_fields;
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,
367
&select_lex->leaf_tables, false) ||
368
session->setup_conds(table_list, conds))
371
TableList *duplicate;
372
if ((duplicate= unique_table(table_list, table_list->next_global)))
374
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
379
if (select_lex->inner_refs_list.elements &&
380
fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
387
/***************************************************************************
389
****************************************************************************/
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
396
bool mysql_truncate(Session& session, TableList *table_list)
399
TransactionServices &transaction_services= TransactionServices::singleton();
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);
408
Safety, in case the engine ignored ha_enable_transaction(false)
409
above. Also clears session->transaction.*.
411
error= transaction_services.autocommitOrRollback(&session, error);
412
session.options= save_options;
417
} /* namespace drizzled */