Drizzled Public API Documentation

sql_delete.cc

00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /*
00017   Delete of records and truncate of tables.
00018 
00019   Multi-table deletes were introduced by Monty and Sinisa
00020 */
00021 #include <config.h>
00022 #include <drizzled/sql_select.h>
00023 #include <drizzled/error.h>
00024 #include <drizzled/probes.h>
00025 #include <drizzled/sql_parse.h>
00026 #include <drizzled/sql_base.h>
00027 #include <drizzled/lock.h>
00028 #include <drizzled/probes.h>
00029 #include <drizzled/optimizer/range.h>
00030 #include <drizzled/records.h>
00031 #include <drizzled/internal/iocache.h>
00032 #include <drizzled/transaction_services.h>
00033 #include <drizzled/filesort.h>
00034 #include <drizzled/sql_lex.h>
00035 
00036 namespace drizzled
00037 {
00038 
00047 bool delete_query(Session *session, TableList *table_list, COND *conds,
00048                   SQL_LIST *order, ha_rows limit, uint64_t,
00049                   bool reset_auto_increment)
00050 {
00051   int   error;
00052   Table   *table;
00053   optimizer::SqlSelect *select= NULL;
00054   ReadRecord  info;
00055   bool          using_limit=limit != HA_POS_ERROR;
00056   bool    transactional_table, const_cond;
00057   bool          const_cond_result;
00058   ha_rows deleted= 0;
00059   uint32_t usable_index= MAX_KEY;
00060   Select_Lex   *select_lex= &session->lex().select_lex;
00061   Session::killed_state_t killed_status= Session::NOT_KILLED;
00062 
00063   if (session->openTablesLock(table_list))
00064   {
00065     DRIZZLE_DELETE_DONE(1, 0);
00066     return true;
00067   }
00068 
00069   table= table_list->table;
00070   assert(table);
00071 
00072   session->set_proc_info("init");
00073   table->map=1;
00074 
00075   if (prepare_delete(session, table_list, &conds))
00076   {
00077     DRIZZLE_DELETE_DONE(1, 0);
00078     return true;
00079   }
00080 
00081   /* check ORDER BY even if it can be ignored */
00082   if (order && order->elements)
00083   {
00084     TableList   tables;
00085     List<Item>   fields;
00086     List<Item>   all_fields;
00087 
00088     tables.table = table;
00089     tables.alias = table_list->alias;
00090 
00091       if (select_lex->setup_ref_array(session, order->elements) ||
00092     setup_order(session, select_lex->ref_pointer_array, &tables,
00093                     fields, all_fields, (Order*) order->first))
00094       {
00095         delete select;
00096         free_underlaid_joins(session, &session->lex().select_lex);
00097         DRIZZLE_DELETE_DONE(1, 0);
00098 
00099         return true;
00100       }
00101   }
00102 
00103   const_cond= (!conds || conds->const_item());
00104 
00105   select_lex->no_error= session->lex().ignore;
00106 
00107   const_cond_result= const_cond && (!conds || conds->val_int());
00108   if (session->is_error())
00109   {
00110     /* Error evaluating val_int(). */
00111     return(true);
00112   }
00113 
00114   /*
00115     Test if the user wants to delete all rows and deletion doesn't have
00116     any side-effects (because of triggers), so we can use optimized
00117     handler::delete_all_rows() method.
00118 
00119     We implement fast TRUNCATE for InnoDB even if triggers are
00120     present.  TRUNCATE ignores triggers.
00121 
00122     We can use delete_all_rows() if and only if:
00123     - We allow new functions (not using option --skip-new), and are
00124       not in safe mode (not using option --safe-mode)
00125     - There is no limit clause
00126     - The condition is constant
00127     - If there is a condition, then it it produces a non-zero value
00128     - If the current command is DELETE FROM with no where clause
00129       (i.e., not TRUNCATE) then:
00130       - We should not be binlogging this statement row-based, and
00131       - there should be no delete triggers associated with the table.
00132   */
00133   if (!using_limit && const_cond_result)
00134   {
00135     /* Update the table->cursor->stats.records number */
00136     table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
00137     ha_rows const maybe_deleted= table->cursor->stats.records;
00138     if (!(error=table->cursor->ha_delete_all_rows()))
00139     {
00140       error= -1;        // ok
00141       deleted= maybe_deleted;
00142       goto cleanup;
00143     }
00144     if (error != HA_ERR_WRONG_COMMAND)
00145     {
00146       table->print_error(error,MYF(0));
00147       error=0;
00148       goto cleanup;
00149     }
00150     /* Handler didn't support fast delete; Delete rows one by one */
00151   }
00152   if (conds)
00153   {
00154     Item::cond_result result;
00155     conds= remove_eq_conds(session, conds, &result);
00156     if (result == Item::COND_FALSE)             // Impossible where
00157       limit= 0;
00158   }
00159 
00160   /* Update the table->cursor->stats.records number */
00161   table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
00162 
00163   table->covering_keys.reset();
00164   table->quick_keys.reset();    // Can't use 'only index'
00165   select= optimizer::make_select(table, 0, 0, conds, 0, &error);
00166   if (error)
00167   {
00168     DRIZZLE_DELETE_DONE(1, 0);
00169     return true;
00170   }
00171 
00172   if ((select && select->check_quick(session, false, limit)) || !limit)
00173   {
00174     delete select;
00175     free_underlaid_joins(session, select_lex);
00176     session->row_count_func= 0;
00177     if (session->is_error())
00178       return true;
00179     DRIZZLE_DELETE_DONE(0, 0);
00184     session->main_da.reset_diagnostics_area();
00185     session->my_ok((ha_rows) session->rowCount());
00186     /*
00187       We don't need to call reset_auto_increment in this case, because
00188       mysql_truncate always gives a NULL conds argument, hence we never
00189       get here.
00190     */
00191     return 0; // Nothing to delete
00192   }
00193 
00194   /* If running in safe sql mode, don't allow updates without keys */
00195   if (table->quick_keys.none())
00196   {
00197     session->server_status|=SERVER_QUERY_NO_INDEX_USED;
00198   }
00199 
00200   if (order && order->elements)
00201   {
00202     uint32_t         length= 0;
00203     SortField  *sortorder;
00204     ha_rows examined_rows;
00205 
00206     if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
00207       usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
00208 
00209     if (usable_index == MAX_KEY)
00210     {
00211       FileSort filesort(*session);
00212       table->sort.io_cache= new internal::IO_CACHE;
00213 
00214 
00215       if (not (sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL)) ||
00216     (table->sort.found_records = filesort.run(table, sortorder, length,
00217                 select, HA_POS_ERROR, 1,
00218                 examined_rows)) == HA_POS_ERROR)
00219       {
00220         delete select;
00221         free_underlaid_joins(session, &session->lex().select_lex);
00222 
00223         DRIZZLE_DELETE_DONE(1, 0);
00224         return true;
00225       }
00226       /*
00227         Filesort has already found and selected the rows we want to delete,
00228         so we don't need the where clause
00229       */
00230       delete select;
00231       free_underlaid_joins(session, select_lex);
00232       select= 0;
00233     }
00234   }
00235 
00236   /* If quick select is used, initialize it before retrieving rows. */
00237   if (select && select->quick && select->quick->reset())
00238   {
00239     delete select;
00240     free_underlaid_joins(session, select_lex);
00241     DRIZZLE_DELETE_DONE(1, 0);
00242     return true;
00243   }
00244 
00245   if (usable_index==MAX_KEY)
00246   {
00247     if ((error= info.init_read_record(session,table,select,1,1)))
00248     {
00249       table->print_error(error, MYF(0));
00250       delete select;
00251       free_underlaid_joins(session, select_lex);
00252       return true;
00253     }
00254   }
00255   else
00256   {
00257     if ((error= info.init_read_record_idx(session, table, 1, usable_index)))
00258     {
00259       table->print_error(error, MYF(0));
00260       delete select;
00261       free_underlaid_joins(session, select_lex);
00262       return true;
00263     }
00264   }
00265 
00266   session->set_proc_info("updating");
00267 
00268   table->mark_columns_needed_for_delete();
00269 
00270   while (!(error=info.read_record(&info)) && !session->getKilled() &&
00271    ! session->is_error())
00272   {
00273     // session->is_error() is tested to disallow delete row on error
00274     if (!(select && select->skip_record())&& ! session->is_error() )
00275     {
00276       if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
00277       {
00278   deleted++;
00279   if (!--limit && using_limit)
00280   {
00281     error= -1;
00282     break;
00283   }
00284       }
00285       else
00286       {
00287   table->print_error(error,MYF(0));
00288   /*
00289     In < 4.0.14 we set the error number to 0 here, but that
00290     was not sensible, because then MySQL would not roll back the
00291     failed DELETE, and also wrote it to the binlog. For MyISAM
00292     tables a DELETE probably never should fail (?), but for
00293     InnoDB it can fail in a FOREIGN KEY error or an
00294     out-of-tablespace error.
00295   */
00296   error= 1;
00297   break;
00298       }
00299     }
00300     else
00301       table->cursor->unlock_row();  // Row failed selection, release lock on it
00302   }
00303   killed_status= session->getKilled();
00304   if (killed_status != Session::NOT_KILLED || session->is_error())
00305     error= 1;         // Aborted
00306 
00307   session->set_proc_info("end");
00308   info.end_read_record();
00309 
00310 cleanup:
00311 
00312   if (reset_auto_increment && (error < 0))
00313   {
00314     /*
00315       We're really doing a truncate and need to reset the table's
00316       auto-increment counter.
00317     */
00318     int error2= table->cursor->ha_reset_auto_increment(0);
00319 
00320     if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
00321     {
00322       table->print_error(error2, MYF(0));
00323       error= 1;
00324     }
00325   }
00326 
00327   delete select;
00328   transactional_table= table->cursor->has_transactions();
00329 
00330   if (!transactional_table && deleted > 0)
00331     session->transaction.stmt.markModifiedNonTransData();
00332 
00333   /* See similar binlogging code in sql_update.cc, for comments */
00334   if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
00335   {
00336     if (session->transaction.stmt.hasModifiedNonTransData())
00337       session->transaction.all.markModifiedNonTransData();
00338   }
00339   assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
00340   free_underlaid_joins(session, select_lex);
00341 
00342   DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
00343   if (error < 0 || (session->lex().ignore && !session->is_fatal_error))
00344   {
00345     session->row_count_func= deleted;
00350     session->main_da.reset_diagnostics_area();
00351     session->my_ok((ha_rows) session->rowCount());
00352   }
00353   session->status_var.deleted_row_count+= deleted;
00354 
00355   return (error >= 0 || session->is_error());
00356 }
00357 
00358 
00359 /*
00360   Prepare items in DELETE statement
00361 
00362   SYNOPSIS
00363     prepare_delete()
00364     session     - thread handler
00365     table_list    - global/local table list
00366     conds   - conditions
00367 
00368   RETURN VALUE
00369     false OK
00370     true  error
00371 */
00372 int prepare_delete(Session *session, TableList *table_list, Item **conds)
00373 {
00374   Select_Lex *select_lex= &session->lex().select_lex;
00375 
00376   List<Item> all_fields;
00377 
00378   session->lex().allow_sum_func= 0;
00379   if (setup_tables_and_check_access(session, &session->lex().select_lex.context,
00380                                     &session->lex().select_lex.top_join_list,
00381                                     table_list,
00382                                     &select_lex->leaf_tables, false) ||
00383       session->setup_conds(table_list, conds))
00384     return(true);
00385   {
00386     TableList *duplicate;
00387     if ((duplicate= unique_table(table_list, table_list->next_global)))
00388     {
00389       my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
00390       return(true);
00391     }
00392   }
00393 
00394   if (select_lex->inner_refs_list.size() &&
00395     fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
00396     return(true);
00397 
00398   return(false);
00399 }
00400 
00401 
00402 /***************************************************************************
00403   TRUNCATE Table
00404 ****************************************************************************/
00405 
00406 /*
00407   Optimize delete of all rows by doing a full generate of the table
00408   This will work even if the .ISM and .ISD tables are destroyed
00409 */
00410 
00411 bool truncate(Session& session, TableList *table_list)
00412 {
00413   bool error;
00414   TransactionServices &transaction_services= TransactionServices::singleton();
00415 
00416   uint64_t save_options= session.options;
00417   table_list->lock_type= TL_WRITE;
00418   session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
00419   init_select(&session.lex());
00420   error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0,
00421                       HA_POS_ERROR, 0L, true);
00422   /*
00423     Safety, in case the engine ignored ha_enable_transaction(false)
00424     above. Also clears session->transaction.*.
00425   */
00426   error= transaction_services.autocommitOrRollback(session, error);
00427   session.options= save_options;
00428 
00429   return error;
00430 }
00431 
00432 } /* namespace drizzled */