mirror of
https://github.com/MariaDB/server.git
synced 2025-05-25 13:42:52 +03:00
BitKeeper/etc/logging_ok: auto-union scripts/make_win_src_distribution.old: Merge rename: scripts/make_win_src_distribution.sh -> scripts/make_win_src_distribution.old BUILD/compile-pentium-debug-max: Auto merged BitKeeper/deleted/.del-sel000001.result~383913ae4505ec86: Auto merged BitKeeper/deleted/.del-sel000001.test~9567c1646058cc: Auto merged Build-tools/Bootstrap: Auto merged Build-tools/Do-compile: Auto merged Docs/Makefile.am: Auto merged client/get_password.c: Auto merged client/mysql.cc: Auto merged client/mysqltest.c: Auto merged extra/perror.c: Auto merged include/config-win.h: Auto merged include/my_sys.h: Auto merged innobase/btr/btr0cur.c: Auto merged innobase/btr/btr0pcur.c: Auto merged innobase/buf/buf0buf.c: Auto merged innobase/buf/buf0flu.c: Auto merged innobase/dict/dict0dict.c: Auto merged innobase/dict/dict0load.c: Auto merged innobase/include/buf0buf.h: Auto merged innobase/include/log0recv.h: Auto merged innobase/include/row0sel.h: Auto merged innobase/include/srv0srv.h: Auto merged innobase/include/ut0mem.h: Auto merged innobase/lock/lock0lock.c: Auto merged innobase/log/log0log.c: Auto merged innobase/mem/mem0pool.c: Auto merged innobase/os/os0file.c: Auto merged innobase/row/row0mysql.c: Auto merged innobase/row/row0sel.c: Auto merged innobase/srv/srv0srv.c: Auto merged innobase/srv/srv0start.c: Auto merged innobase/trx/trx0sys.c: Auto merged innobase/trx/trx0trx.c: Auto merged innobase/ut/ut0mem.c: Auto merged innobase/ut/ut0ut.c: Auto merged myisam/ft_boolean_search.c: Auto merged myisam/mi_check.c: Auto merged myisam/mi_extra.c: Auto merged myisam/mi_key.c: Auto merged myisam/myisamdef.h: Auto merged myisammrg/myrg_queue.c: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/ctype_latin1_de.result: Auto merged mysql-test/r/flush.result: Auto merged mysql-test/r/func_time.result: Auto merged mysql-test/r/grant_cache.result: Auto merged mysql-test/r/join.result: Auto merged mysql-test/r/join_outer.result: Auto merged mysql-test/r/range.result: Auto merged mysql-test/r/rpl000018.result: Auto merged mysql-test/r/rpl_insert_id.result: Auto merged mysql-test/r/rpl_master_pos_wait.result: Auto merged mysql-test/r/rpl_relayspace.result: Auto merged mysql-test/r/select_safe.result: Auto merged mysql-test/r/symlink.result: Auto merged mysql-test/r/type_date.result: Auto merged mysql-test/r/type_datetime.result: Auto merged mysql-test/t/alias.test: Auto merged mysql-test/t/ctype_latin1_de.test: Auto merged mysql-test/t/fulltext_left_join.test: Auto merged mysql-test/t/func_time.test: Auto merged mysql-test/t/handler.test: Auto merged mysql-test/t/heap.test: Auto merged mysql-test/t/join.test: Auto merged mysql-test/t/join_outer.test: Auto merged mysql-test/t/order_by.test: Auto merged mysql-test/t/range.test: Auto merged mysql-test/t/rpl000001.test: Auto merged mysql-test/t/rpl000018.test: Auto merged mysql-test/t/rpl_insert_id.test: Auto merged mysql-test/t/sel000100.test: Auto merged mysql-test/t/select_safe.test: Auto merged mysql-test/t/type_date.test: Auto merged mysql-test/t/type_datetime.test: Auto merged mysql-test/t/user_var.test: Auto merged mysys/default.c: Auto merged mysys/mf_format.c: Auto merged mysys/my_getopt.c: Auto merged mysys/thr_lock.c: Auto merged mysys/tree.c: Auto merged scripts/Makefile.am: Auto merged scripts/mysql_install_db.sh: Auto merged scripts/mysqld_safe.sh: Auto merged sql/Makefile.am: Auto merged sql/field_conv.cc: Auto merged sql/ha_innodb.h: Auto merged sql/ha_myisam.cc: Auto merged sql/ha_myisammrg.h: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item.h: Auto merged sql/item_func.cc: Auto merged sql/item_timefunc.cc: Auto merged sql/net_serv.cc: Auto merged sql/nt_servc.cc: Auto merged sql/opt_range.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.h: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_list.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_rename.cc: Auto merged sql/sql_repl.h: Auto merged sql/sql_update.cc: Auto merged sql/table.cc: Auto merged sql/table.h: Auto merged sql/uniques.cc: Auto merged support-files/mysql.spec.sh: Auto merged vio/viosocket.c: Auto merged BitKeeper/deleted/.del-ctype-latin1_de.c~c5d8f9208bceb98e: merge BitKeeper/deleted/.del-mini_client.cc~8677895ec8169183: merge acinclude.m4: Merge with 4.0 (openssl patch) client/mysqlbinlog.cc: Merge with 4.0 in which we had added code from 4.1 (We are basicly only using the 4.1 code here) configure.in: Keep 4.1 file heap/hp_open.c: merge with 4.0 include/my_base.h: merge with 4.0 include/my_global.h: merge with 4.0 include/mysqld_error.h: merge with 4.0 innobase/ha/ha0ha.c: merge with 4.0 (Code should be same but we use indentaion from 4.0) innobase/log/log0recv.c: merge with 4.0 libmysql/libmysql.c: Remove with 4.0 code that was ported from 4.1 libmysqld/lib_sql.cc: merge with 4.0 myisam/mi_open.c: Remove 4.0 specific code myisam/myisamchk.c: merge with 4.0 myisammrg/myrg_rkey.c: merge with 4.0 mysql-test/r/alter_table.result: May need to be fixed after merge mysql-test/r/create.result: May need to be fixed after merge mysql-test/r/distinct.result: May need to be fixed after merge mysql-test/r/drop.result: May need to be fixed after merge mysql-test/r/fulltext.result: May need to be fixed after merge mysql-test/r/func_set.result: May need to be fixed after merge mysql-test/r/func_str.result: May need to be fixed after merge mysql-test/r/func_test.result: May need to be fixed after merge mysql-test/r/grant.result: May need to be fixed after merge mysql-test/r/group_by.result: May need to be fixed after merge mysql-test/r/handler.result: May need to be fixed after merge mysql-test/r/heap.result: May need to be fixed after merge mysql-test/r/innodb.result: May need to be fixed after merge mysql-test/r/insert.result: May need to be fixed after merge mysql-test/r/insert_select.result: May need to be fixed after merge mysql-test/r/key_diff.result: May need to be fixed after merge mysql-test/r/merge.result: May need to be fixed after merge mysql-test/r/myisam.result: May need to be fixed after merge mysql-test/r/order_by.result: May need to be fixed after merge mysql-test/r/query_cache.result: May need to be fixed after merge mysql-test/r/rpl_flush_log_loop.result: May need to be fixed after merge mysql-test/r/rpl_loaddata.result: May need to be fixed after merge mysql-test/r/rpl_log.result: May need to be fixed after merge mysql-test/r/rpl_log_pos.result: May need to be fixed after merge mysql-test/r/rpl_rotate_logs.result: May need to be fixed after merge mysql-test/r/select.result: May need to be fixed after merge mysql-test/r/union.result: May need to be fixed after merge mysql-test/r/user_var.result: May need to be fixed after merge mysql-test/t/alter_table.test: merge with 4.0 mysql-test/t/create.test: merge with 4.0 mysql-test/t/distinct.test: merge with 4.0 mysql-test/t/drop.test: merge with 4.0 mysql-test/t/flush.test: merge with 4.0 mysql-test/t/fulltext.test: merge with 4.0 mysql-test/t/func_set.test: merge with 4.0 mysql-test/t/func_str.test: merge with 4.0 mysql-test/t/func_test.test: merge with 4.0 mysql-test/t/grant.test: merge with 4.0 mysql-test/t/grant_cache.test: merge with 4.0 mysql-test/t/innodb.test: Add back EXPLAIN and SHOW KEYS statements, but make them independent of number of rows returned by InnoDB mysql-test/t/insert.test: merge with 4.0 mysql-test/t/insert_select.test: merge with 4.0 mysql-test/t/merge.test: merge with 4.0 mysql-test/t/query_cache.test: merge with 4.0 mysql-test/t/rpl_flush_log_loop.test: merge with 4.0 mysql-test/t/rpl_loaddata.test: merge with 4.0 mysql-test/t/rpl_rotate_logs.test: merge with 4.0 mysql-test/t/select.test: merge with 4.0 mysql-test/t/symlink.test: merge with 4.0 mysql-test/t/union.test: merge with 4.0 mysys/charset.c: merge with 4.0 scripts/mysql_fix_privilege_tables.sh: merge with 4.0 (Add quoting for some variables) sql/field.h: merge with 4.0 sql/ha_innodb.cc: merge with 4.0 sql/item_cmpfunc.cc: merge with 4.0 sql/item_cmpfunc.h: merge with 4.0 sql/item_func.h: merge with 4.0 sql/item_strfunc.cc: merge with 4.0 Fixed null handling with ELT() sql/item_timefunc.h: merge with 4.0 sql/lex.h: merge with 4.0 sql/log.cc: merge with 4.0 sql/log_event.cc: Merge with 4.0 Cleanups: - Indentation - #endif comments - Replace strmov() with *pos++= for two byte strings - Moved variable declarations to start of functions - Merged identical code (LOAD_EVENT) - Added casts when subtracting pointers Did a full diff between this and 4.0 to ensure that the file is correct after merge. sql/log_event.h: merge with 4.0 sql/mysql_priv.h: merge with 4.0 sql/mysqld.cc: merge with 4.0 sql/repl_failsafe.cc: merge with 4.0 sql/set_var.cc: merge with 4.0 sql/set_var.h: merge with 4.0 sql/share/czech/errmsg.txt: merge with 4.0 sql/share/danish/errmsg.txt: merge with 4.0 sql/share/dutch/errmsg.txt: merge with 4.0 sql/share/english/errmsg.txt: merge with 4.0 sql/share/estonian/errmsg.txt: merge with 4.0 sql/share/french/errmsg.txt: merge with 4.0 sql/share/german/errmsg.txt: merge with 4.0 sql/share/greek/errmsg.txt: merge with 4.0 sql/share/hungarian/errmsg.txt: merge with 4.0 sql/share/italian/errmsg.txt: merge with 4.0 sql/share/japanese/errmsg.txt: merge with 4.0 sql/share/korean/errmsg.txt: merge with 4.0 sql/share/norwegian-ny/errmsg.txt: merge with 4.0 sql/share/norwegian/errmsg.txt: merge with 4.0 sql/share/polish/errmsg.txt: merge with 4.0 sql/share/portuguese/errmsg.txt: merge with 4.0 sql/share/romanian/errmsg.txt: merge with 4.0 sql/share/russian/errmsg.txt: merge with 4.0 sql/share/slovak/errmsg.txt: merge with 4.0 sql/share/spanish/errmsg.txt: merge with 4.0 sql/share/swedish/errmsg.txt: merge with 4.0 sql/share/ukrainian/errmsg.txt: merge with 4.0 sql/slave.cc: Merge + some indentation fixes sql/slave.h: merge with 4.0 sql/sql_acl.cc: merge with 4.0 Some end space removal to make it easier to do future merges sql/sql_acl.h: merge with 4.0 sql/sql_cache.cc: merge with 4.0 sql/sql_class.h: merge with 4.0 sql/sql_handler.cc: merge with 4.0 sql/sql_lex.cc: merge with 4.0 sql/sql_lex.h: merge with 4.0 sql/sql_parse.cc: merge with 4.0 sql/sql_repl.cc: merge with 4.0 sql/sql_select.cc: merge with 4.0 sql/sql_table.cc: merge with 4.0 sql/sql_union.cc: Merge with 4.0 Note that I couldn't find out how to merge OPTION_FOUND_ROWS handling so this has to be fixed later sql/sql_yacc.yy: merge with 4.0 Removed end space to make merge easier vio/Makefile.am: merge with 4.0
640 lines
18 KiB
C++
640 lines
18 KiB
C++
/* Copyright (C) 2000 MySQL 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 and truncate of tables.
|
|
|
|
Multi-table deletes were introduced by Monty and Sinisa
|
|
*/
|
|
|
|
|
|
|
|
#include "mysql_priv.h"
|
|
#include "ha_innodb.h"
|
|
#include "sql_select.h"
|
|
|
|
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
|
|
ha_rows limit, ulong options)
|
|
{
|
|
int error;
|
|
TABLE *table;
|
|
SQL_SELECT *select=0;
|
|
READ_RECORD info;
|
|
bool using_limit=limit != HA_POS_ERROR;
|
|
bool transactional_table, log_delayed, safe_update, const_cond;
|
|
ha_rows deleted;
|
|
TABLE_LIST *delete_table_list= (TABLE_LIST*)
|
|
thd->lex.select_lex.table_list.first;
|
|
DBUG_ENTER("mysql_delete");
|
|
|
|
if ((open_and_lock_tables(thd, table_list)))
|
|
DBUG_RETURN(-1);
|
|
fix_tables_pointers(thd->lex.all_selects_list);
|
|
table= table_list->table;
|
|
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
|
thd->proc_info="init";
|
|
table->map=1;
|
|
if (setup_conds(thd, delete_table_list, &conds) ||
|
|
setup_ftfuncs(&thd->lex.select_lex))
|
|
DBUG_RETURN(-1);
|
|
if (find_real_table_in_list(table_list->next,
|
|
table_list->db, table_list->real_name))
|
|
{
|
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
const_cond= (!conds || conds->const_item());
|
|
safe_update=test(thd->options & OPTION_SAFE_UPDATES);
|
|
if (safe_update && const_cond)
|
|
{
|
|
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
|
DBUG_RETURN(1);
|
|
}
|
|
|
|
/* Test if the user wants to delete all rows */
|
|
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
|
|
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
|
|
{
|
|
deleted= table->file->records;
|
|
if (!(error=table->file->delete_all_rows()))
|
|
{
|
|
error= -1; // ok
|
|
goto cleanup;
|
|
}
|
|
if (error != HA_ERR_WRONG_COMMAND)
|
|
{
|
|
table->file->print_error(error,MYF(0));
|
|
error=0;
|
|
goto cleanup;
|
|
}
|
|
/* Handler didn't support fast delete; Delete rows one by one */
|
|
}
|
|
|
|
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(safe_update, limit)) || !limit)
|
|
{
|
|
delete select;
|
|
free_underlaid_joins(thd, &thd->lex.select_lex);
|
|
send_ok(thd,0L);
|
|
DBUG_RETURN(0); // Nothing to delete
|
|
}
|
|
|
|
/* If running in safe sql mode, don't allow updates without keys */
|
|
if (!table->quick_keys)
|
|
{
|
|
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
|
|
if (safe_update && !using_limit)
|
|
{
|
|
delete select;
|
|
free_underlaid_joins(thd, &thd->lex.select_lex);
|
|
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
if (options & OPTION_QUICK)
|
|
(void) table->file->extra(HA_EXTRA_QUICK);
|
|
|
|
if (order)
|
|
{
|
|
uint length;
|
|
SORT_FIELD *sortorder;
|
|
TABLE_LIST tables;
|
|
List<Item> fields;
|
|
List<Item> all_fields;
|
|
ha_rows examined_rows;
|
|
|
|
bzero((char*) &tables,sizeof(tables));
|
|
tables.table = table;
|
|
|
|
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
|
|
MYF(MY_FAE | MY_ZEROFILL));
|
|
if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
|
|
all_fields.elements)||
|
|
setup_order(thd, thd->lex.select_lex.ref_pointer_array, &tables,
|
|
fields, all_fields, order) ||
|
|
!(sortorder=make_unireg_sortorder(order, &length)) ||
|
|
(table->sort.found_records = filesort(thd, table, sortorder, length,
|
|
(SQL_SELECT *) 0, HA_POS_ERROR,
|
|
&examined_rows))
|
|
== HA_POS_ERROR)
|
|
{
|
|
delete select;
|
|
free_underlaid_joins(thd, &thd->lex.select_lex);
|
|
DBUG_RETURN(-1); // This will force out message
|
|
}
|
|
}
|
|
|
|
init_read_record(&info,thd,table,select,1,1);
|
|
deleted=0L;
|
|
init_ftfuncs(thd, &thd->lex.select_lex, 1);
|
|
thd->proc_info="updating";
|
|
while (!(error=info.read_record(&info)) && !thd->killed &&
|
|
!thd->net.report_error)
|
|
{
|
|
// thd->net.report_error is tested to disallow delete row on error
|
|
if (!(select && select->skipp_record())&& !thd->net.report_error )
|
|
{
|
|
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));
|
|
/*
|
|
In < 4.0.14 we set the error number to 0 here, but that
|
|
was not sensible, because then MySQL would not roll back the
|
|
failed DELETE, and also wrote it to the binlog. For MyISAM
|
|
tables a DELETE probably never should fail (?), but for
|
|
InnoDB it can fail in a FOREIGN KEY error or an
|
|
out-of-tablespace error.
|
|
*/
|
|
error= 1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
table->file->unlock_row(); // Row failed selection, release lock on it
|
|
}
|
|
thd->proc_info="end";
|
|
end_read_record(&info);
|
|
free_io_cache(table); // Will not do any harm
|
|
if (options & OPTION_QUICK)
|
|
(void) table->file->extra(HA_EXTRA_NORMAL);
|
|
|
|
cleanup:
|
|
/*
|
|
Invalidate the table in the query cache if something changed. This must
|
|
be before binlog writing and ha_autocommit_...
|
|
*/
|
|
if (deleted)
|
|
{
|
|
query_cache_invalidate3(thd, table_list, 1);
|
|
}
|
|
|
|
transactional_table= table->file->has_transactions();
|
|
log_delayed= (transactional_table || table->tmp_table);
|
|
if (deleted && (error <= 0 || !transactional_table))
|
|
{
|
|
mysql_update_log.write(thd,thd->query, thd->query_length);
|
|
if (mysql_bin_log.is_open())
|
|
{
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
|
log_delayed);
|
|
if (mysql_bin_log.write(&qinfo) && transactional_table)
|
|
error=1;
|
|
}
|
|
if (!log_delayed)
|
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
|
}
|
|
if (transactional_table)
|
|
{
|
|
if (ha_autocommit_or_rollback(thd,error >= 0))
|
|
error=1;
|
|
}
|
|
|
|
if (thd->lock)
|
|
{
|
|
mysql_unlock_tables(thd, thd->lock);
|
|
thd->lock=0;
|
|
}
|
|
delete select;
|
|
free_underlaid_joins(thd, &thd->lex.select_lex);
|
|
if (error >= 0 || thd->net.report_error)
|
|
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
|
|
else
|
|
{
|
|
send_ok(thd,deleted);
|
|
DBUG_PRINT("info",("%d records deleted",deleted));
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Delete multiple tables from join
|
|
***************************************************************************/
|
|
|
|
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
|
|
|
|
extern "C" int refposcmp2(void* arg, const void *a,const void *b)
|
|
{
|
|
/* arg is a pointer to file->ref_length */
|
|
return memcmp(a,b, *(int*) arg);
|
|
}
|
|
|
|
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
|
|
uint num_of_tables_arg)
|
|
: delete_tables(dt), thd(thd_arg), deleted(0),
|
|
num_of_tables(num_of_tables_arg), error(0),
|
|
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
|
|
{
|
|
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
|
|
}
|
|
|
|
|
|
int
|
|
multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|
{
|
|
DBUG_ENTER("multi_delete::prepare");
|
|
unit= u;
|
|
do_delete= 1;
|
|
thd->proc_info="deleting from main table";
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
bool
|
|
multi_delete::initialize_tables(JOIN *join)
|
|
{
|
|
TABLE_LIST *walk;
|
|
Unique **tempfiles_ptr;
|
|
DBUG_ENTER("initialize_tables");
|
|
|
|
if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
|
|
DBUG_RETURN(1);
|
|
|
|
table_map tables_to_delete_from=0;
|
|
for (walk= delete_tables ; walk ; walk=walk->next)
|
|
tables_to_delete_from|= walk->table->map;
|
|
|
|
walk= delete_tables;
|
|
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
|
|
tab < end;
|
|
tab++)
|
|
{
|
|
if (tab->table->map & tables_to_delete_from)
|
|
{
|
|
/* We are going to delete from this table */
|
|
TABLE *tbl=walk->table=tab->table;
|
|
walk=walk->next;
|
|
/* Don't use KEYREAD optimization on this table */
|
|
tbl->no_keyread=1;
|
|
tbl->used_keys= 0;
|
|
if (tbl->file->has_transactions())
|
|
log_delayed= transactional_tables= 1;
|
|
else if (tbl->tmp_table != NO_TMP_TABLE)
|
|
log_delayed= 1;
|
|
else
|
|
normal_tables= 1;
|
|
}
|
|
}
|
|
walk= delete_tables;
|
|
tempfiles_ptr= tempfiles;
|
|
for (walk=walk->next ; walk ; walk=walk->next)
|
|
{
|
|
TABLE *table=walk->table;
|
|
*tempfiles_ptr++= new Unique (refposcmp2,
|
|
(void *) &table->file->ref_length,
|
|
table->file->ref_length,
|
|
MEM_STRIP_BUF_SIZE);
|
|
}
|
|
init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
|
|
DBUG_RETURN(thd->is_fatal_error != 0);
|
|
}
|
|
|
|
|
|
multi_delete::~multi_delete()
|
|
{
|
|
for (table_being_deleted=delete_tables ;
|
|
table_being_deleted ;
|
|
table_being_deleted=table_being_deleted->next)
|
|
{
|
|
TABLE *t=table_being_deleted->table;
|
|
free_io_cache(t); // Alloced by unique
|
|
t->no_keyread=0;
|
|
}
|
|
|
|
for (uint counter= 0; counter < num_of_tables-1; counter++)
|
|
{
|
|
if (tempfiles[counter])
|
|
delete tempfiles[counter];
|
|
}
|
|
}
|
|
|
|
|
|
bool multi_delete::send_data(List<Item> &values)
|
|
{
|
|
int secure_counter= -1;
|
|
DBUG_ENTER("multi_delete::send_data");
|
|
|
|
for (table_being_deleted=delete_tables ;
|
|
table_being_deleted ;
|
|
table_being_deleted=table_being_deleted->next, secure_counter++)
|
|
{
|
|
TABLE *table=table_being_deleted->table;
|
|
|
|
/* Check if we are using outer join and we didn't find the row */
|
|
if (table->status & (STATUS_NULL_ROW | STATUS_DELETED))
|
|
continue;
|
|
|
|
table->file->position(table->record[0]);
|
|
|
|
if (secure_counter < 0)
|
|
{
|
|
/* If this is the table we are scanning */
|
|
table->status|= STATUS_DELETED;
|
|
if (!(error=table->file->delete_row(table->record[0])))
|
|
deleted++;
|
|
else if (!table_being_deleted->next)
|
|
{
|
|
table->file->print_error(error,MYF(0));
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error=tempfiles[secure_counter]->unique_add((char*) table->file->ref);
|
|
if (error)
|
|
{
|
|
error=-1;
|
|
DBUG_RETURN(1);
|
|
}
|
|
}
|
|
}
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
void multi_delete::send_error(uint errcode,const char *err)
|
|
{
|
|
DBUG_ENTER("multi_delete::send_error");
|
|
|
|
/* First send error what ever it is ... */
|
|
::send_error(thd,errcode,err);
|
|
|
|
/* If nothing deleted return */
|
|
if (!deleted)
|
|
DBUG_VOID_RETURN;
|
|
|
|
/* Something already deleted so we have to invalidate cache */
|
|
query_cache_invalidate3(thd, delete_tables, 1);
|
|
|
|
/* Below can happen when thread is killed early ... */
|
|
if (!table_being_deleted)
|
|
table_being_deleted=delete_tables;
|
|
|
|
/*
|
|
If rows from the first table only has been deleted and it is
|
|
transactional, just do rollback.
|
|
The same if all tables are transactional, regardless of where we are.
|
|
In all other cases do attempt deletes ...
|
|
*/
|
|
if ((table_being_deleted->table->file->has_transactions() &&
|
|
table_being_deleted == delete_tables) || !normal_tables)
|
|
ha_rollback_stmt(thd);
|
|
else if (do_delete)
|
|
{
|
|
VOID(do_deletes(1));
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Do delete from other tables.
|
|
Returns values:
|
|
0 ok
|
|
1 error
|
|
*/
|
|
|
|
int multi_delete::do_deletes(bool from_send_error)
|
|
{
|
|
int local_error= 0, counter= 0;
|
|
DBUG_ENTER("do_deletes");
|
|
|
|
if (from_send_error)
|
|
{
|
|
/* Found out table number for 'table_being_deleted' */
|
|
for (TABLE_LIST *aux=delete_tables;
|
|
aux != table_being_deleted;
|
|
aux=aux->next)
|
|
counter++;
|
|
}
|
|
else
|
|
table_being_deleted = delete_tables;
|
|
|
|
do_delete= 0;
|
|
for (table_being_deleted=table_being_deleted->next;
|
|
table_being_deleted ;
|
|
table_being_deleted=table_being_deleted->next, counter++)
|
|
{
|
|
TABLE *table = table_being_deleted->table;
|
|
if (tempfiles[counter]->get(table))
|
|
{
|
|
local_error=1;
|
|
break;
|
|
}
|
|
|
|
READ_RECORD info;
|
|
init_read_record(&info,thd,table,NULL,0,1);
|
|
/*
|
|
Ignore any rows not found in reference tables as they may already have
|
|
been deleted by foreign key handling
|
|
*/
|
|
info.ignore_not_found_rows= 1;
|
|
while (!(local_error=info.read_record(&info)) && !thd->killed)
|
|
{
|
|
if ((local_error=table->file->delete_row(table->record[0])))
|
|
{
|
|
table->file->print_error(local_error,MYF(0));
|
|
break;
|
|
}
|
|
deleted++;
|
|
}
|
|
end_read_record(&info);
|
|
if (local_error == -1) // End of file
|
|
local_error = 0;
|
|
}
|
|
DBUG_RETURN(local_error);
|
|
}
|
|
|
|
|
|
/*
|
|
Send ok to the client
|
|
|
|
return: 0 sucess
|
|
1 error
|
|
*/
|
|
|
|
bool multi_delete::send_eof()
|
|
{
|
|
thd->proc_info="deleting from reference tables";
|
|
|
|
/* Does deletes for the last n - 1 tables, returns 0 if ok */
|
|
int local_error= do_deletes(0); // returns 0 if success
|
|
|
|
/* reset used flags */
|
|
thd->proc_info="end";
|
|
|
|
/*
|
|
We must invalidate the query cache before binlog writing and
|
|
ha_autocommit_...
|
|
*/
|
|
if (deleted)
|
|
query_cache_invalidate3(thd, delete_tables, 1);
|
|
|
|
/*
|
|
Write the SQL statement to the binlog if we deleted
|
|
rows and we succeeded, or also in an error case when there
|
|
was a non-transaction-safe table involved, since
|
|
modifications in it cannot be rolled back.
|
|
*/
|
|
if (deleted && (error <= 0 || normal_tables))
|
|
{
|
|
mysql_update_log.write(thd,thd->query,thd->query_length);
|
|
if (mysql_bin_log.is_open())
|
|
{
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
|
log_delayed);
|
|
if (mysql_bin_log.write(&qinfo) && !normal_tables)
|
|
local_error=1; // Log write failed: roll back the SQL statement
|
|
}
|
|
if (!log_delayed)
|
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
|
}
|
|
/* Commit or rollback the current SQL statement */
|
|
if (transactional_tables)
|
|
if (ha_autocommit_or_rollback(thd,local_error > 0))
|
|
local_error=1;
|
|
|
|
if (local_error)
|
|
::send_error(thd);
|
|
else
|
|
::send_ok(thd, deleted);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
TRUNCATE TABLE
|
|
****************************************************************************/
|
|
|
|
/*
|
|
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
|
|
|
|
dont_send_ok should be set if:
|
|
- We should always wants to generate the table (even if the table type
|
|
normally can't safely do this.
|
|
- We don't want an ok to be sent to the end user.
|
|
- We don't want to log the truncate command
|
|
- If we want to have a name lock on the table on exit without errors.
|
|
*/
|
|
|
|
int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
|
|
{
|
|
HA_CREATE_INFO create_info;
|
|
char path[FN_REFLEN];
|
|
TABLE **table_ptr;
|
|
int error;
|
|
DBUG_ENTER("mysql_truncate");
|
|
|
|
/* If it is a temporary table, close and regenerate it */
|
|
if (!dont_send_ok && (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;
|
|
create_info.table_charset=table->table_charset;
|
|
|
|
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);
|
|
// We don't need to call invalidate() because this table is not in cache
|
|
if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
|
|
table_list->real_name, 1))))
|
|
(void) rm_temporary_table(table_type, path);
|
|
/*
|
|
If we return here we will not have logged the truncation to the bin log
|
|
and we will not send_ok() to the client.
|
|
*/
|
|
goto end;
|
|
}
|
|
|
|
(void) sprintf(path,"%s/%s/%s%s",mysql_data_home,table_list->db,
|
|
table_list->real_name,reg_ext);
|
|
fn_format(path,path,"","",4);
|
|
|
|
if (!dont_send_ok)
|
|
{
|
|
db_type table_type;
|
|
if ((table_type=get_table_type(path)) == DB_TYPE_UNKNOWN)
|
|
{
|
|
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
|
|
table_list->real_name);
|
|
DBUG_RETURN(-1);
|
|
}
|
|
if (!ha_supports_generate(table_type))
|
|
{
|
|
/* Probably InnoDB table */
|
|
table_list->lock_type= TL_WRITE;
|
|
DBUG_RETURN(mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0,
|
|
HA_POS_ERROR, 0));
|
|
}
|
|
if (lock_and_wait_for_table_name(thd, table_list))
|
|
DBUG_RETURN(-1);
|
|
}
|
|
|
|
bzero((char*) &create_info,sizeof(create_info));
|
|
create_info.table_charset=table_list->table->table_charset;
|
|
|
|
*fn_ext(path)=0; // Remove the .frm extension
|
|
error= ha_create_table(path,&create_info,1) ? -1 : 0;
|
|
query_cache_invalidate3(thd, table_list, 0);
|
|
|
|
end:
|
|
if (!dont_send_ok)
|
|
{
|
|
if (!error)
|
|
{
|
|
mysql_update_log.write(thd,thd->query,thd->query_length);
|
|
if (mysql_bin_log.is_open())
|
|
{
|
|
Query_log_event qinfo(thd, thd->query, thd->query_length,
|
|
thd->tmp_table);
|
|
mysql_bin_log.write(&qinfo);
|
|
}
|
|
send_ok(thd); // This should return record count
|
|
}
|
|
VOID(pthread_mutex_lock(&LOCK_open));
|
|
unlock_table_name(thd, table_list);
|
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
|
}
|
|
else if (error)
|
|
{
|
|
VOID(pthread_mutex_lock(&LOCK_open));
|
|
unlock_table_name(thd, table_list);
|
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
|
}
|
|
DBUG_RETURN(error ? -1 : 0);
|
|
}
|