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 #include <drizzled/diagnostics_area.h>
00036 #include <drizzled/statistics_variables.h>
00037 #include <drizzled/session/transactions.h>
00038 
00039 namespace drizzled {
00040 
00049 bool delete_query(Session *session, TableList *table_list, COND *conds,
00050                   SQL_LIST *order, ha_rows limit, uint64_t,
00051                   bool reset_auto_increment)
00052 {
00053   int   error;
00054   Table   *table;
00055   optimizer::SqlSelect *select= NULL;
00056   ReadRecord  info;
00057   bool          using_limit=limit != HA_POS_ERROR;
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     select_lex->setup_ref_array(session, order->elements);
00092     if (setup_order(session, select_lex->ref_pointer_array, &tables, fields, all_fields, (Order*) order->first))
00093     {
00094       delete select;
00095       free_underlaid_joins(session, &session->lex().select_lex);
00096       DRIZZLE_DELETE_DONE(1, 0);
00097 
00098       return true;
00099     }
00100   }
00101 
00102   bool const_cond= not conds || conds->const_item();
00103 
00104   select_lex->no_error= session->lex().ignore;
00105 
00106   bool const_cond_result= const_cond && (!conds || conds->val_int());
00107   if (session->is_error())
00108   {
00109     /* Error evaluating val_int(). */
00110     return true;
00111   }
00112 
00113   /*
00114     Test if the user wants to delete all rows and deletion doesn't have
00115     any side-effects (because of triggers), so we can use optimized
00116     handler::delete_all_rows() method.
00117 
00118     We implement fast TRUNCATE for InnoDB even if triggers are
00119     present.  TRUNCATE ignores triggers.
00120 
00121     We can use delete_all_rows() if and only if:
00122     - We allow new functions (not using option --skip-new), and are
00123       not in safe mode (not using option --safe-mode)
00124     - There is no limit clause
00125     - The condition is constant
00126     - If there is a condition, then it it produces a non-zero value
00127     - If the current command is DELETE FROM with no where clause
00128       (i.e., not TRUNCATE) then:
00129       - We should not be binlogging this statement row-based, and
00130       - there should be no delete triggers associated with the table.
00131   */
00132   if (!using_limit && const_cond_result)
00133   {
00134     /* Update the table->cursor->stats.records number */
00135     table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
00136     ha_rows const maybe_deleted= table->cursor->stats.records;
00137     if (!(error=table->cursor->ha_delete_all_rows()))
00138     {
00139       error= -1;        // ok
00140       deleted= maybe_deleted;
00141       goto cleanup;
00142     }
00143     if (error != HA_ERR_WRONG_COMMAND)
00144     {
00145       table->print_error(error,MYF(0));
00146       error=0;
00147       goto cleanup;
00148     }
00149     /* Handler didn't support fast delete; Delete rows one by one */
00150   }
00151   if (conds)
00152   {
00153     Item::cond_result result;
00154     conds= remove_eq_conds(session, conds, &result);
00155     if (result == Item::COND_FALSE)             // Impossible where
00156       limit= 0;
00157   }
00158 
00159   /* Update the table->cursor->stats.records number */
00160   table->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
00161 
00162   table->covering_keys.reset();
00163   table->quick_keys.reset();    // Can't use 'only index'
00164   select= optimizer::make_select(table, 0, 0, conds, 0, &error);
00165   if (error)
00166   {
00167     DRIZZLE_DELETE_DONE(1, 0);
00168     return true;
00169   }
00170 
00171   if ((select && select->check_quick(session, false, limit)) || !limit)
00172   {
00173     delete select;
00174     free_underlaid_joins(session, select_lex);
00175     session->row_count_func= 0;
00176     if (session->is_error())
00177       return true;
00178     DRIZZLE_DELETE_DONE(0, 0);
00183     session->main_da().reset_diagnostics_area();
00184     session->my_ok((ha_rows) session->rowCount());
00185     /*
00186       We don't need to call reset_auto_increment in this case, because
00187       mysql_truncate always gives a NULL conds argument, hence we never
00188       get here.
00189     */
00190     return 0; // Nothing to delete
00191   }
00192 
00193   /* If running in safe sql mode, don't allow updates without keys */
00194   if (table->quick_keys.none())
00195   {
00196     session->server_status|=SERVER_QUERY_NO_INDEX_USED;
00197   }
00198 
00199   if (order && order->elements)
00200   {
00201     if ((!select || table->quick_keys.none()) && limit != HA_POS_ERROR)
00202       usable_index= optimizer::get_index_for_order(table, (Order*)(order->first), limit);
00203 
00204     if (usable_index == MAX_KEY)
00205     {
00206       FileSort filesort(*session);
00207       table->sort.io_cache= new internal::io_cache_st;
00208       uint32_t length= 0;
00209       SortField* sortorder= make_unireg_sortorder((Order*) order->first, &length, NULL);
00210       ha_rows examined_rows;
00211       if ((table->sort.found_records= filesort.run(table, sortorder, length, select, HA_POS_ERROR, 1, examined_rows)) == HA_POS_ERROR)
00212       {
00213         delete select;
00214         free_underlaid_joins(session, &session->lex().select_lex);
00215 
00216         DRIZZLE_DELETE_DONE(1, 0);
00217         return true;
00218       }
00219       /*
00220         Filesort has already found and selected the rows we want to delete,
00221         so we don't need the where clause
00222       */
00223       delete select;
00224       free_underlaid_joins(session, select_lex);
00225       select= 0;
00226     }
00227   }
00228 
00229   /* If quick select is used, initialize it before retrieving rows. */
00230   if (select && select->quick && select->quick->reset())
00231   {
00232     delete select;
00233     free_underlaid_joins(session, select_lex);
00234     DRIZZLE_DELETE_DONE(1, 0);
00235     return true;
00236   }
00237 
00238   if (usable_index==MAX_KEY)
00239   {
00240     if ((error= info.init_read_record(session,table,select,1,1)))
00241     {
00242       table->print_error(error, MYF(0));
00243       delete select;
00244       free_underlaid_joins(session, select_lex);
00245       return true;
00246     }
00247   }
00248   else
00249   {
00250     if ((error= info.init_read_record_idx(session, table, 1, usable_index)))
00251     {
00252       table->print_error(error, MYF(0));
00253       delete select;
00254       free_underlaid_joins(session, select_lex);
00255       return true;
00256     }
00257   }
00258 
00259   session->set_proc_info("updating");
00260 
00261   table->mark_columns_needed_for_delete();
00262 
00263   while (!(error=info.read_record(&info)) && !session->getKilled() &&
00264    ! session->is_error())
00265   {
00266     // session->is_error() is tested to disallow delete row on error
00267     if (!(select && select->skip_record())&& ! session->is_error() )
00268     {
00269       if (!(error= table->cursor->deleteRecord(table->getInsertRecord())))
00270       {
00271   deleted++;
00272   if (!--limit && using_limit)
00273   {
00274     error= -1;
00275     break;
00276   }
00277       }
00278       else
00279       {
00280   table->print_error(error,MYF(0));
00281   /*
00282     In < 4.0.14 we set the error number to 0 here, but that
00283     was not sensible, because then MySQL would not roll back the
00284     failed DELETE, and also wrote it to the binlog. For MyISAM
00285     tables a DELETE probably never should fail (?), but for
00286     InnoDB it can fail in a FOREIGN KEY error or an
00287     out-of-tablespace error.
00288   */
00289   error= 1;
00290   break;
00291       }
00292     }
00293     else
00294       table->cursor->unlock_row();  // Row failed selection, release lock on it
00295   }
00296   killed_status= session->getKilled();
00297   if (killed_status != Session::NOT_KILLED || session->is_error())
00298     error= 1;         // Aborted
00299 
00300   session->set_proc_info("end");
00301   info.end_read_record();
00302 
00303 cleanup:
00304 
00305   if (reset_auto_increment && (error < 0))
00306   {
00307     /*
00308       We're really doing a truncate and need to reset the table's
00309       auto-increment counter.
00310     */
00311     int error2= table->cursor->ha_reset_auto_increment(0);
00312 
00313     if (error2 && (error2 != HA_ERR_WRONG_COMMAND))
00314     {
00315       table->print_error(error2, MYF(0));
00316       error= 1;
00317     }
00318   }
00319 
00320   delete select;
00321   bool transactional_table= table->cursor->has_transactions();
00322 
00323   if (!transactional_table && deleted > 0)
00324     session->transaction.stmt.markModifiedNonTransData();
00325 
00326   /* See similar binlogging code in sql_update.cc, for comments */
00327   if ((error < 0) || session->transaction.stmt.hasModifiedNonTransData())
00328   {
00329     if (session->transaction.stmt.hasModifiedNonTransData())
00330       session->transaction.all.markModifiedNonTransData();
00331   }
00332   assert(transactional_table || !deleted || session->transaction.stmt.hasModifiedNonTransData());
00333   free_underlaid_joins(session, select_lex);
00334 
00335   DRIZZLE_DELETE_DONE((error >= 0 || session->is_error()), deleted);
00336   if (error < 0 || (session->lex().ignore && !session->is_fatal_error))
00337   {
00338     session->row_count_func= deleted;
00343     session->main_da().reset_diagnostics_area();
00344     session->my_ok((ha_rows) session->rowCount());
00345   }
00346   session->status_var.deleted_row_count+= deleted;
00347 
00348   return (error >= 0 || session->is_error());
00349 }
00350 
00351 
00352 /*
00353   Prepare items in DELETE statement
00354 
00355   SYNOPSIS
00356     prepare_delete()
00357     session     - thread handler
00358     table_list    - global/local table list
00359     conds   - conditions
00360 
00361   RETURN VALUE
00362     false OK
00363     true  error
00364 */
00365 int prepare_delete(Session *session, TableList *table_list, Item **conds)
00366 {
00367   Select_Lex *select_lex= &session->lex().select_lex;
00368   session->lex().allow_sum_func= 0;
00369   if (setup_tables_and_check_access(session, &session->lex().select_lex.context, &select_lex->top_join_list, 
00370     table_list, &select_lex->leaf_tables, false) ||
00371       session->setup_conds(table_list, conds))
00372     return true;
00373 
00374   if (unique_table(table_list, table_list->next_global))
00375   {
00376     my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->alias);
00377     return true;
00378   }
00379   List<Item> all_fields;
00380   if (select_lex->inner_refs_list.size() && fix_inner_refs(session, all_fields, select_lex, select_lex->ref_pointer_array))
00381     return true;
00382   return false;
00383 }
00384 
00385 
00386 /***************************************************************************
00387   TRUNCATE Table
00388 ****************************************************************************/
00389 
00390 /*
00391   Optimize delete of all rows by doing a full generate of the table
00392   This will work even if the .ISM and .ISD tables are destroyed
00393 */
00394 
00395 bool truncate(Session& session, TableList *table_list)
00396 {
00397   uint64_t save_options= session.options;
00398   table_list->lock_type= TL_WRITE;
00399   session.options&= ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
00400   init_select(&session.lex());
00401   int error= delete_query(&session, table_list, (COND*) 0, (SQL_LIST*) 0, HA_POS_ERROR, 0L, true);
00402   /*
00403     Safety, in case the engine ignored ha_enable_transaction(false)
00404     above. Also clears session->transaction.*.
00405   */
00406   error= TransactionServices::autocommitOrRollback(session, error);
00407   session.options= save_options;
00408   return error;
00409 }
00410 
00411 } /* namespace drizzled */