summaryrefslogtreecommitdiff
path: root/sql/sql_delete.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_delete.cc')
-rw-r--r--sql/sql_delete.cc213
1 files changed, 213 insertions, 0 deletions
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
new file mode 100644
index 00000000000..5d21a089283
--- /dev/null
+++ b/sql/sql_delete.cc
@@ -0,0 +1,213 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/* Delete of records */
+
+#include "mysql_priv.h"
+
+/*
+ Optimize delete of all rows by doing a full generate of the table
+ This will work even if the .ISM and .ISD tables are destroyed
+*/
+
+static int generate_table(THD *thd, TABLE_LIST *table_list,
+ TABLE *locked_table)
+{
+ char path[FN_REFLEN];
+ int error;
+ TABLE **table_ptr;
+ DBUG_ENTER("generate_table");
+
+ thd->proc_info="generate_table";
+ /* If it is a temporary table, close and regenerate it */
+ if ((table_ptr=find_temporary_table(thd,table_list->db,
+ table_list->real_name)))
+ {
+ TABLE *table= *table_ptr;
+ HA_CREATE_INFO create_info;
+ table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.auto_increment_value= table->file->auto_increment_value;
+ db_type table_type=table->db_type;
+
+ strmov(path,table->path);
+ *table_ptr= table->next; // Unlink table from list
+ close_temporary(table,0);
+ *fn_ext(path)=0; // Remove the .frm extension
+ ha_create_table(path, &create_info,1);
+ if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
+ table_list->real_name, 1))))
+ {
+ (void) rm_temporary_table(table_type, path);
+ }
+ }
+ else
+ {
+ (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
+ table_list->real_name,reg_ext);
+ fn_format(path,path,"","",4);
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if (locked_table)
+ mysql_lock_abort(thd,locked_table); // end threads waiting on lock
+ // close all copies in use
+ if (remove_table_from_cache(thd,table_list->db,table_list->real_name))
+ {
+ if (!locked_table)
+ {
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ DBUG_RETURN(1); // We must get a lock on table
+ }
+ }
+ if (locked_table)
+ locked_table->file->extra(HA_EXTRA_FORCE_REOPEN);
+ if (thd->locked_tables)
+ close_data_tables(thd,table_list->db,table_list->real_name);
+ else
+ close_thread_tables(thd,1);
+ HA_CREATE_INFO create_info;
+ bzero((char*) &create_info,sizeof(create_info));
+ *fn_ext(path)=0; // Remove the .frm extension
+ error= ha_create_table(path,&create_info,1) ? -1 : 0;
+ if (thd->locked_tables && reopen_tables(thd,1,0))
+ error= -1;
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ }
+ if (!error)
+ {
+ send_ok(&thd->net); // This should return record count
+ mysql_update_log.write(thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ DBUG_RETURN(error ? -1 : 0);
+}
+
+
+int mysql_delete(THD *thd,TABLE_LIST *table_list,COND *conds,ha_rows limit,
+ thr_lock_type lock_type)
+{
+ int error;
+ TABLE *table;
+ SQL_SELECT *select;
+ READ_RECORD info;
+ bool using_limit=limit != HA_POS_ERROR;
+ bool use_generate_table;
+ DBUG_ENTER("mysql_delete");
+
+ if (!table_list->db)
+ table_list->db=thd->db;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !conds)
+ {
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
+
+ use_generate_table= (!using_limit && !conds &&
+ !(specialflag &
+ (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
+ (thd->options & OPTION_AUTO_COMMIT));
+ if (use_generate_table && ! thd->open_tables)
+ {
+ error=generate_table(thd,table_list,(TABLE*) 0);
+ if (error <= 0)
+ DBUG_RETURN(error); // Error or ok
+ }
+ if (!(table = open_ltable(thd,table_list,
+ limit != HA_POS_ERROR ? TL_WRITE_LOW_PRIORITY :
+ lock_type)))
+ DBUG_RETURN(-1);
+ thd->proc_info="init";
+ if (use_generate_table)
+ DBUG_RETURN(generate_table(thd,table_list,table));
+ table->map=1;
+ if (setup_conds(thd,table_list,&conds))
+ DBUG_RETURN(-1);
+
+ table->used_keys=table->quick_keys=0; // Can't use 'only index'
+ select=make_select(table,0,0,conds,&error);
+ if (error)
+ DBUG_RETURN(-1);
+ if (select && select->check_quick(test(thd->options & SQL_SAFE_UPDATES),
+ limit))
+ {
+ delete select;
+ send_ok(&thd->net,0L);
+ DBUG_RETURN(0);
+ }
+
+ /* If running in safe sql mode, don't allow updates without keys */
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys &&
+ limit == HA_POS_ERROR)
+ {
+ delete select;
+ send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
+
+ (void) table->file->extra(HA_EXTRA_NO_READCHECK);
+ init_read_record(&info,thd,table,select,1,1);
+ ulong deleted=0L;
+ thd->proc_info="updating";
+ while (!(error=info.read_record(&info)) && !thd->killed)
+ {
+ if (!(select && select->skipp_record()))
+ {
+ if (!(error=table->file->delete_row(table->record[0])))
+ {
+ deleted++;
+ if (!--limit && using_limit)
+ {
+ error= -1;
+ break;
+ }
+ }
+ else
+ {
+ table->file->print_error(error,MYF(0));
+ error=0;
+ break;
+ }
+ }
+ }
+ thd->proc_info="end";
+ end_read_record(&info);
+ VOID(table->file->extra(HA_EXTRA_READCHECK));
+ if (deleted)
+ {
+ mysql_update_log.write(thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ if (ha_autocommit_or_rollback(thd,error >= 0))
+ error=1;
+ if (thd->lock)
+ {
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
+ }
+ delete select;
+ if (error >= 0) // Fatal error
+ send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
+ else
+ {
+ send_ok(&thd->net,deleted);
+ DBUG_PRINT("info",("%d records deleted",deleted));
+ }
+ DBUG_RETURN(0);
+}
+
+