Drizzled Public API Documentation

sql_delete.cc
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 #include <drizzled/sql_lex.h>
35 #include <drizzled/diagnostics_area.h>
36 #include <drizzled/statistics_variables.h>
37 #include <drizzled/session/transactions.h>
38 
39 namespace drizzled {
40 
49 bool delete_query(Session *session, TableList *table_list, COND *conds,
50  SQL_LIST *order, ha_rows limit, uint64_t,
51  bool reset_auto_increment)
52 {
53  int error;
54  Table *table;
55  optimizer::SqlSelect *select= NULL;
56  ReadRecord info;
57  bool using_limit=limit != HA_POS_ERROR;
58  ha_rows deleted= 0;
59  uint32_t usable_index= MAX_KEY;
60  Select_Lex *select_lex= &session->lex().select_lex;
61  Session::killed_state_t killed_status= Session::NOT_KILLED;
62 
63  if (session->openTablesLock(table_list))
64  {
65  DRIZZLE_DELETE_DONE(1, 0);
66  return true;
67  }
68 
69  table= table_list->table;
70  assert(table);
71 
72  session->set_proc_info("init");
73  table->map=1;
74 
75  if (prepare_delete(session, table_list, &conds))
76  {
77  DRIZZLE_DELETE_DONE(1, 0);
78  return true;
79  }
80 
81  /* check ORDER BY even if it can be ignored */
82  if (order && order->elements)
83  {
84  TableList tables;
85  List<Item> fields;
86  List<Item> all_fields;
87 
88  tables.table = table;
89  tables.alias = table_list->alias;
90 
91  select_lex->setup_ref_array(session, order->elements);
92  if (setup_order(session, select_lex->ref_pointer_array, &tables, 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  bool const_cond= not conds || conds->const_item();
103 
104  select_lex->no_error= session->lex().ignore;
105 
106  bool 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  */
128  if (!using_limit && const_cond_result)
129  {
130  /* Update the table->cursor->stats.records number */
131  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
132  ha_rows const maybe_deleted= table->cursor->stats.records;
133  if (!(error=table->cursor->ha_delete_all_rows()))
134  {
135  error= -1; // ok
136  deleted= maybe_deleted;
137  goto cleanup;
138  }
139  if (error != HA_ERR_WRONG_COMMAND)
140  {
141  table->print_error(error,MYF(0));
142  error=0;
143  goto cleanup;
144  }
145  /* Handler didn't support fast delete; Delete rows one by one */
146  }
147  if (conds)
148  {
149  Item::cond_result result;
150  conds= remove_eq_conds(session, conds, &result);
151  if (result == Item::COND_FALSE) // Impossible where
152  limit= 0;
153  }
154 
155  /* Update the table->cursor->stats.records number */
156  table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
157 
158  table->covering_keys.reset();
159  table->quick_keys.reset(); // Can't use 'only index'
160  select= optimizer::make_select(table, 0, 0, conds, 0, &error);
161  if (error)
162  {
163  DRIZZLE_DELETE_DONE(1, 0);
164  return true;
165  }
166 
167  if ((select && select->check_quick(session, false, limit)) || !limit)
168  {
169  delete select;
170  free_underlaid_joins(session, select_lex);
171  session->row_count_func= 0;
172  if (session->is_error())
173  return true;
174  DRIZZLE_DELETE_DONE(0, 0);
179  session->main_da().reset_diagnostics_area();
180  session->my_ok((ha_rows) session->rowCount());
181  /*
182  We don't need to call reset_auto_increment in this case, because
183  mysql_truncate always gives a NULL conds argument, hence we never
184  get here.
185  */
186  return 0; // Nothing to delete
187  }
188 
189  /* If running in safe sql mode, don't allow updates without keys */
190  if (table->quick_keys.none())
191  {
192  session->server_status|=SERVER_QUERY_NO_INDEX_USED;
193  }
194 
195  if (order && order->elements)
196  {
197  if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
198  usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
199 
200  if (usable_index == MAX_KEY)
201  {
202  FileSort filesort(*session);
203  table->sort.io_cache= new internal::io_cache_st;
204  uint32_t length= 0;
205  SortField* sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL);
206  ha_rows examined_rows;
207  if ((table->sort.found_records= filesort.run(table, sortorder, length, select, HA_POS_ERROR, 1, examined_rows)) == HA_POS_ERROR)
208  {
209  delete select;
210  free_underlaid_joins(session, &session->lex().select_lex);
211 
212  DRIZZLE_DELETE_DONE(1, 0);
213  return true;
214  }
215  /*
216  Filesort has already found and selected the rows we want to delete,
217  so we don't need the where clause
218  */
219  delete select;
220  free_underlaid_joins(session, select_lex);
221  select= 0;
222  }
223  }
224 
225  /* If quick select is used, initialize it before retrieving rows. */
226  if (select && select->quick && select->quick->reset())
227  {
228  delete select;
229  free_underlaid_joins(session, select_lex);
230  DRIZZLE_DELETE_DONE(1, 0);
231  return true;
232  }
233 
234  if (usable_index==MAX_KEY)
235  {
236  if ((error= info.init_read_record(session,table,select,1,1)))
237  {
238  table->print_error(error, MYF(0));
239  delete select;
240  free_underlaid_joins(session, select_lex);
241  return true;
242  }
243  }
244  else
245  {
246  if ((error= info.init_read_record_idx(session, table, 1, usable_index)))
247  {
248  table->print_error(error, MYF(0));
249  delete select;
250  free_underlaid_joins(session, select_lex);
251  return true;
252  }
253  }
254 
255  session->set_proc_info("updating");
256 
257  table->mark_columns_needed_for_delete();
258 
259  while (!(error=info.read_record(&info)) && !session->getKilled() &&
260  ! session->is_error())
261  {
262  // session->is_error() is tested to disallow delete row on error
263  if (!(select && select->skip_record())&& ! session->is_error() )
264  {
265  if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
266  {
267  deleted++;
268  if (!--limit && using_limit)
269  {
270  error= -1;
271  break;
272  }
273  }
274  else
275  {
276  table->print_error(error,MYF(0));
277  error= 1;
278  break;
279  }
280  }
281  else
282  table->cursor->unlock_row(); // Row failed selection, release lock on it
283  }
284  killed_status= session->getKilled();
285  if (killed_status != Session::NOT_KILLED || session->is_error())
286  error= 1; // Aborted
287 
288  session->set_proc_info("end");
289  info.end_read_record();
290 
291 cleanup:
292 
293  if (reset_auto_increment && (error < 0))
294  {
295  /*
296  We're really doing a truncate and need to reset the table's
297  auto-increment counter.
298  */
299  int error2= table->cursor->ha_reset_auto_increment(0);
300 
301  if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
302  {
303  table->print_error(error2, MYF(0));
304  error= 1;
305  }
306  }
307 
308  delete select;
309  bool transactional_table= table->cursor->has_transactions();
310 
311  if (!transactional_table && deleted > 0)
312  session->transaction.stmt.markModifiedNonTransData();
313 
314  if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
315  {
316  if (session->transaction.stmt.hasModifiedNonTransData())
317  session->transaction.all.markModifiedNonTransData();
318  }
319  assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
320  free_underlaid_joins(session, select_lex);
321 
322  DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
323  if (error < 0 || (session->lex().ignore && !session->is_fatal_error))
324  {
325  session->row_count_func= deleted;
330  session->main_da().reset_diagnostics_area();
331  session->my_ok((ha_rows) session->rowCount());
332  }
333  session->status_var.deleted_row_count+= deleted;
334 
335  return (error >= 0 || session->is_error());
336 }
337 
338 
339 /*
340  Prepare items in DELETE statement
341 
342  SYNOPSIS
343  prepare_delete()
344  session - thread handler
345  table_list - global/local table list
346  conds - conditions
347 
348  RETURN VALUE
349  false OK
350  true error
351 */
352 int prepare_delete(Session *session, TableList *table_list, Item **conds)
353 {
354  Select_Lex *select_lex= &session->lex().select_lex;
355  session->lex().allow_sum_func= 0;
356  if (setup_tables_and_check_access(session, &session->lex().select_lex.context, &select_lex->top_join_list,
357  table_list, &select_lex->leaf_tables, false) ||
358  session->setup_conds(table_list, conds))
359  return true;
360 
361  if (unique_table(table_list, table_list->next_global))
362  {
363  my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
364  return true;
365  }
366  List<Item> all_fields;
367  if (select_lex->inner_refs_list.size() && fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
368  return true;
369  return false;
370 }
371 
372 
373 /***************************************************************************
374  TRUNCATE Table
375 ****************************************************************************/
376 
377 /*
378  Optimize delete of all rows by doing a full generate of the table
379  This will work even if the .ISM and .ISD tables are destroyed
380 */
381 
382 bool truncate(Session& session, TableList *table_list)
383 {
384  uint64_t save_options= session.options;
385  table_list->lock_type= TL_WRITE;
386  session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
387  init_select(&session.lex());
388  int error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0, HA_POS_ERROR, 0L, true);
389  /*
390  Safety, in case the engine ignored ha_enable_transaction(false)
391  above. Also clears session->transaction.*.
392  */
393  error= TransactionServices::autocommitOrRollback(session, error);
394  session.options= save_options;
395  return error;
396 }
397 
398 } /* namespace drizzled */
virtual bool const_item() const
Definition: item.h:495
void my_ok(ha_rows affected_rows=0, ha_rows found_rows_arg=0, uint64_t passed_id=0, const char *message=NULL)
Definition: session.cc:1877
table_map map
ID bit of table (1,2,4,8,16...)
Definition: table.h:270
void set_proc_info(const char *info)
Definition: session.h:609
virtual int64_t val_int()=0
bool delete_query(Session *session, TableList *table_list, COND *conds, SQL_LIST *order, ha_rows rows, uint64_t options, bool reset_auto_increment)
Definition: sql_delete.cc:49
COND * remove_eq_conds(Session *session, COND *cond, Item::cond_result *cond_value)
Definition: sql_select.cc:2851
Table * table
opened table
Definition: table_list.h:145
QuickSelectInterface * quick
Definition: range.h:277
int ha_delete_all_rows()
Definition: cursor.cc:636
int ha_reset_auto_increment(uint64_t value)
Definition: cursor.cc:665
ha_rows run(Table *table, SortField *sortorder, uint32_t s_length, optimizer::SqlSelect *select, ha_rows max_rows, bool sort_positions, ha_rows &examined_rows)
Definition: filesort.cc:187
int init_read_record_idx(Session *session, Table *table, bool print_error, uint32_t idx) __attribute__((warn_unused_result))
Definition: records.cc:53
int setup_order(Session *session, Item **ref_pointer_array, TableList *tables, List< Item > &fields, List< Item > &all_fields, Order *order)
Definition: sql_select.cc:5908
bool is_fatal_error
Definition: session.h:540
void free_underlaid_joins(Session *session, Select_Lex *select)
Definition: sql_select.cc:6655
Cursor * cursor
Definition: table.h:68
int64_t row_count_func
Definition: session.h:401
static int autocommitOrRollback(Session &, int error)
bool openTablesLock(TableList *)
Definition: session.cc:1767
bool is_error() const
Definition: session.cc:1871